我一直在开发我的第一个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
在我看来,我有两个属性ScaleY
和ScaleTransform
,我在用户在画布上滚动时设置这些属性。在我之前的代码隐藏版本中,我将使用这些属性创建LayoutTransform
,并使用public partial class GraphOverview : Page
{
public double ScaleX { get; set; }
public double ScaleY { get; set; }
将其应用于指定的画布。
ScaleX
这个版本的问题是我无法绕过它来使用我的新XAML代码。我希望ScaleY
中ScaleTransform
的{{1}}和ItemsPanelTemplate
属性绑定到我视图中的属性。只有,正常ElementName
绑定由于某种原因不起作用。更清楚的是,画布大概不知道视图,我假设它是一个模板。而且,即使它有一个名字,我也无法从后面的代码中调用画布。
我尝试了几种解决方案,对RelativeResources
等进行了摸索,但我认为我不清楚为什么ItemsPanelTemplate
与XAML代码中的其他内容断开连接。提前谢谢!
更新
也许我应该澄清一下,通过将ScaleX
和ScaleY
属性移动到ViewModel并绑定到这些属性,可以轻松解决这个问题。但在我看来,这些特定于View的属性不应该驻留在ViewModel中。
答案 0 :(得分:1)
当您说视图特定信息不应位于视图模型中时,您是正确的。但在您的情况下,位置成为模型的一部分,因为位置只不过是您的视图应该基于的数据。在这种情况下,您可以将它们视为模型的一部分而不是视图。编写一个单独的Model Class,并在ViewModel类的可观察集合中使用它。我希望它能清除你的怀疑。
public class Node
{
public double ScaleX { get; set; }
public double ScaleY { get; set; }
}
修改强>
回答你的问题。 -
但是“缩放”属性指定了“画布”的行为方式,因此“视图”还没有作为“模型”吗?为了设置单个Canvas的缩放属性,创建一个新模型对我来说似乎是多余的?视图应仅关注绘制数据,并且由于属性用作这些绘图的修改,它们属于视图,不是吗?
您想根据提供的数据绘制图表。 Node类将为您提供数据。它存储数据而不是画布应该呈现的逻辑,XAML代码使用这些数据并具有在视图中显示它的逻辑。
那么View还没有作为“模特”吗?
您尝试过的实现在视图中具有模型,其目的是将模型与视图分开。最初创建一个类只是为了保存2个double值可能看起来多余。但是如果你将它们从视图中抽象出来有一些优点。
通常,ScaleX和ScaleY将成为视图的一部分,但在您的情况下,它们会更改并存储数据。因此,您需要将此ScaleX和ScaleY抽象到另一个层中以保留MVVM概念。
答案 1 :(得分:0)
我不确定您是否设置了视图的DataContext,这有助于显示更多代码
internal ViewModel viewModel { get; set; }
public View()
{
DataContext = (viewModel = new ViewModel());
}
您是否将ObservableCollection绑定到节点的ItemSource?我不熟悉绘画,但是当我与孩子们联系时,我从未取得过成绩。
但我只开发了大约4个利用MVVM的项目。