将数据从视图绑定到ItemsPanelTemplate

时间:2014-04-08 22:30:16

标签: c# wpf mvvm binding

我一直在开发我的第一个MVVM WPF应用程序,我想在其中绘制一个包含节点和边缘的图形。目前,我在我的视图后面的代码中执行所有绘制逻辑,迭代节点,相应地创建形状并将它们添加到画布。

因为我不想跟踪形状,只想根据给定的数据(即节点)绘制它们,我决定创建ObservableCollection Nodes Edges 1}}和ItemsControl,并将<ItemsControl x:Name="ItemsControlCanvas" ItemsSource="{Binding Path=Nodes}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas> <Canvas.LayoutTransform> <ScaleTransform ScaleX="{Binding ?}" ScaleY="{Binding ?}"/> </Canvas.LayoutTransform> </Canvas> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Ellipse Fill="Blue" Width="4" Height="4" /> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemContainerStyle> <Style> <Setter Property="Canvas.Top" Value="{Binding Path=Position.Y}" /> <Setter Property="Canvas.Left" Value="{Binding Path=Position.X}" /> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> 绑定到这些以便自动绘制形状。

现在我专注于绘制节点,并提出以下XAML代码:

ScaleX

在我看来,我有两个属性ScaleYScaleTransform,我在用户在画布上滚动时设置这些属性。在我之前的代码隐藏版本中,我将使用这些属性创建LayoutTransform,并使用public partial class GraphOverview : Page { public double ScaleX { get; set; } public double ScaleY { get; set; } 将其应用于指定的画布。

ScaleX

这个版本的问题是我无法绕过它来使用我的新XAML代码。我希望ScaleYScaleTransform的{​​{1}}和ItemsPanelTemplate属性绑定到我视图中的属性。只有,正常ElementName绑定由于某种原因不起作用。更清楚的是,画布大概不知道视图,我假设它是一个模板。而且,即使它有一个名字,我也无法从后面的代码中调用画布。

我尝试了几种解决方案,对RelativeResources等进行了摸索,但我认为我不清楚为什么ItemsPanelTemplate与XAML代码中的其他内容断开连接。提前谢谢!

更新

也许我应该澄清一下,通过将ScaleXScaleY属性移动到ViewModel并绑定到这些属性,可以轻松解决这个问题。但在我看来,这些特定于View的属性不应该驻留在ViewModel中。

2 个答案:

答案 0 :(得分:1)

当您说视图特定信息不应位于视图模型中时,您是正确的。但在您的情况下,位置成为模型的一部分,因为位置只不过是您的视图应该基于的数据。在这种情况下,您可以将它们视为模型的一部分而不是视图。编写一个单独的Model Class,并在ViewModel类的可观察集合中使用它。我希望它能清除你的怀疑。

public class Node
{
    public double ScaleX { get; set; }
    public double ScaleY { get; set; }
}

修改
回答你的问题。 -

但是“缩放”属性指定了“画布”的行为方式,因此“视图”还没有作为“模型”吗?为了设置单个Canvas的缩放属性,创建一个新模型对我来说似乎是多余的?视图应仅关注绘制数据,并且由于属性用作这些绘图的修改,它们属于视图,不是吗?

您想根据提供的数据绘制图表。 Node类将为您提供数据。它存储数据而不是画布应该呈现的逻辑,XAML代码使用这些数据并具有在视图中显示它的逻辑。

那么View还没有作为“模特”吗?

您尝试过的实现在视图中具有模型,其目的是将模型与视图分开。最初创建一个类只是为了保存2个double值可能看起来多余。但是如果你将它们从视图中抽象出来有一些优点。

  • 在视图模型中,您可以为此Node类(Model)创建一个可观察的集合。如果您在视图中具有ScaleX和ScaleY,则无法从Viewmodel访问它。
  • 将来您可能希望将ScaleX和ScaleY更改为不同的比例,例如Logarmic scale /不同单位。在这种情况下,您必须更改ViewModel中的逻辑才能执行此操作,并且不必担心更改View。但是,如果在视图中有此Observable集合,则必须更改视图以更改数据/模型。
  • 最后 - 您可以为ViewModel中的任何内容编写单元测试,但不能查看View。

通常,ScaleX和ScaleY将成为视图的一部分,但在您的情况下,它们会更改并存储数据。因此,您需要将此ScaleX和ScaleY抽象到另一个层中以保留MVVM概念。

答案 1 :(得分:0)

我不确定您是否设置了视图的DataContext,这有助于显示更多代码

internal ViewModel viewModel { get; set; }

public View()
{
      DataContext = (viewModel = new ViewModel());
}

您是否将ObservableCollection绑定到节点的ItemSource?我不熟悉绘画,但是当我与孩子们联系时,我从未取得过成绩。

但我只开发了大约4个利用MVVM的项目。