是基于 ObservableCollection 实现 DrawingVisual 的 MVVM WPF 方法
Is the a MVVM WPF way to implement DrawingVisual based on an ObservableCollection
我的应用程序在 canvas 上显示了很多行和 polygons/paths。
我的 ViewModel 包含一系列 ObservableCollections
,代表要绘制的不同项目。
我遇到的问题是应用程序缩放和平移速度非常慢。
缩放和平移全部由 IvalueConverter
处理,并从世界坐标系转换为 canvas 坐标系。
为此,我必须 NotifyPropertyChange
所有 objects 在屏幕上可见,以强制使用最新的平移和缩放值重新绘制它们。
对于几百行它工作得很好,但是对于几千行它就非常慢了。如果你缩小,那么所有 objects 都可见,因此受到 NotifyPropertyChange
的影响,超过 10,000 行几乎无法使用。
我没有以任何方式使用多边形 built-in 功能,因为所有处理、选择移动等都在视图模型中处理。
因此,我想尝试使用 DrawingVisual
而不是 Shapes
,因为我知道它们的开销要低得多,但我找不到任何好的 MVVM 示例来说明如何使用它们。
我看到的示例显示它们是在代码隐藏中构建的,这不是我认为我应该使用它们的方式。
举例如下:
//new DrawingVisual
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);
drawingContext.Close();
//creating a Host as follows:
public MyVisualHost()
{
_children = new VisualCollection(this);
_children.Add(CreateDrawingVisualRectangle());
_children.Add(CreateDrawingVisualText());
_children.Add(CreateDrawingVisualEllipses());
this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
}
除非有一种 WPF 方法可以使用 DrawingVisual
绑定到我的可观察对象 collection,否则我需要在我的模型中创建和删除绘图 objects。 Every-time 更新了一个模型,然后必须更新我的 drawingVisual
。但是后来我在模型中创建视图项目,这不是正确的方法。
谁能建议我应该如何在我的 MVVM 应用程序中实现 DrawingVisual
而不是 Shapes
?
这是我目前使用的代码的摘录,它使用 Shapes
XAML
<ItemsControl x:Name="Catchments">
<ItemsControl.Resources>
<CollectionViewSource x:Key="CatchmentPolygons" Source="{Binding Path=NetworkMain.Catchments}"></CollectionViewSource>
<DataTemplate DataType="{x:Type cad:Catchment}">
<Polygon
Stroke="{Binding IsSelected, Mode=OneWay, Converter={StaticResource ObjectColour}, ConverterParameter=Catchment}"
StrokeThickness="1"
Visibility="{Binding Visible, Mode=OneWay, TargetNullValue='Hidden'}"
Points="{Binding Points, Mode=OneWay, Converter={StaticResource CollectionPointConverter}}">
<Polygon.Fill>
<SolidColorBrush
Color="{Binding IsSelected, Mode=OneWay, Converter={StaticResource ObjectColour}, ConverterParameter=Catchment}"
Opacity=".25"
>
</SolidColorBrush>
</Polygon.Fill>
</Polygon>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource CatchmentPolygons}}"></CollectionContainer>
</CompositeCollection>
</ItemsControl.ItemsSource>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas
ClipToBounds="true">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
我的 Observable Collections 在我的 ViewModel
:
public ObservableCollection<Conduit> Conduits { get; set; } = new();
public ObservableCollection<Node> Nodes { get; set; } = new();
public ObservableCollection<Catchment> Catchments { get; set; } = new();
编辑
具有放大和缩小视图的 Canvas 屏幕截图:
缩小:
图像缩放了一点,但实际上,线宽、节点大小和箭头在放大和缩小时保持不变。只有节点的投影坐标发生变化。
放大:
您可以将依赖项 属性 添加到您的可视化宿主并将其绑定到视图模型的源 属性。
然后可视化主机可以为源集合中的每个项目创建一个DrawingVisual
我的应用程序在 canvas 上显示了很多行和 polygons/paths。
我的 ViewModel 包含一系列 ObservableCollections
,代表要绘制的不同项目。
我遇到的问题是应用程序缩放和平移速度非常慢。
缩放和平移全部由 IvalueConverter
处理,并从世界坐标系转换为 canvas 坐标系。
为此,我必须 NotifyPropertyChange
所有 objects 在屏幕上可见,以强制使用最新的平移和缩放值重新绘制它们。
对于几百行它工作得很好,但是对于几千行它就非常慢了。如果你缩小,那么所有 objects 都可见,因此受到 NotifyPropertyChange
的影响,超过 10,000 行几乎无法使用。
我没有以任何方式使用多边形 built-in 功能,因为所有处理、选择移动等都在视图模型中处理。
因此,我想尝试使用 DrawingVisual
而不是 Shapes
,因为我知道它们的开销要低得多,但我找不到任何好的 MVVM 示例来说明如何使用它们。
我看到的示例显示它们是在代码隐藏中构建的,这不是我认为我应该使用它们的方式。
举例如下:
//new DrawingVisual
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);
drawingContext.Close();
//creating a Host as follows:
public MyVisualHost()
{
_children = new VisualCollection(this);
_children.Add(CreateDrawingVisualRectangle());
_children.Add(CreateDrawingVisualText());
_children.Add(CreateDrawingVisualEllipses());
this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
}
除非有一种 WPF 方法可以使用 DrawingVisual
绑定到我的可观察对象 collection,否则我需要在我的模型中创建和删除绘图 objects。 Every-time 更新了一个模型,然后必须更新我的 drawingVisual
。但是后来我在模型中创建视图项目,这不是正确的方法。
谁能建议我应该如何在我的 MVVM 应用程序中实现 DrawingVisual
而不是 Shapes
?
这是我目前使用的代码的摘录,它使用 Shapes
XAML
<ItemsControl x:Name="Catchments">
<ItemsControl.Resources>
<CollectionViewSource x:Key="CatchmentPolygons" Source="{Binding Path=NetworkMain.Catchments}"></CollectionViewSource>
<DataTemplate DataType="{x:Type cad:Catchment}">
<Polygon
Stroke="{Binding IsSelected, Mode=OneWay, Converter={StaticResource ObjectColour}, ConverterParameter=Catchment}"
StrokeThickness="1"
Visibility="{Binding Visible, Mode=OneWay, TargetNullValue='Hidden'}"
Points="{Binding Points, Mode=OneWay, Converter={StaticResource CollectionPointConverter}}">
<Polygon.Fill>
<SolidColorBrush
Color="{Binding IsSelected, Mode=OneWay, Converter={StaticResource ObjectColour}, ConverterParameter=Catchment}"
Opacity=".25"
>
</SolidColorBrush>
</Polygon.Fill>
</Polygon>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource CatchmentPolygons}}"></CollectionContainer>
</CompositeCollection>
</ItemsControl.ItemsSource>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas
ClipToBounds="true">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
我的 Observable Collections 在我的 ViewModel
:
public ObservableCollection<Conduit> Conduits { get; set; } = new();
public ObservableCollection<Node> Nodes { get; set; } = new();
public ObservableCollection<Catchment> Catchments { get; set; } = new();
编辑
具有放大和缩小视图的 Canvas 屏幕截图:
缩小:
图像缩放了一点,但实际上,线宽、节点大小和箭头在放大和缩小时保持不变。只有节点的投影坐标发生变化。
放大:
您可以将依赖项 属性 添加到您的可视化宿主并将其绑定到视图模型的源 属性。
然后可视化主机可以为源集合中的每个项目创建一个DrawingVisual