我想将我的 code-behind 项目切换到 MVVM 设计。,但我在这方面遇到了一些麻烦。
我有画布面板,我想创建网格线作为背景。
在后面的代码中,我将网格逐行添加到画布面板。首次初始化、缩放、平移等功能非常快。
这些是创建网格方法的代码隐藏代码。
private void CreateGridLines()
{
// draw lines
for (int x = -4000; x <= 4000; x += 100)
{
Line verticalLine = new Line
{
Stroke = new SolidColorBrush(Color.FromArgb(0xFF, 0x66, 0x66, 0x66)),
X1 = x,
Y1 = -4000,
X2 = x,
Y2 = 4000,
StrokeThickness = 1,
};
canvas.Children.Add(verticalLine);
}
for (int y = -4000; y <= 4000; y += 100)
{
Line horizontalLine = new Line
{
Stroke = new SolidColorBrush(Color.FromArgb(0xFF, 0x66, 0x66, 0x66)),
X1 = -4000,
Y1 = y,
X2 = 4000,
Y2 = y,
StrokeThickness = 1,
};
canvas.Children.Add(horizontalLine);
}
}
在 MVVM 模式中,我创建 ObservableCollection 来动态更新 UI。
我逐行添加了所有网格。这是可行的,但是在首次初始化、缩放、平移等功能时,视图的反应变得非常慢。
仅仅因为网格线,总共大约有 160 个元素被添加到列表中。
每次添加一行都会引发事件。所以我猜这使得应用程序很重。我尝试了 BindingList,但无法获得与代码隐藏方式一样高的效率。
所以我决定立即将网格添加到可观察集合中,而不是逐行添加。
我想我必须创建网格作为由 System.Windows.Shapes 派生的自定义形状,然后我会将这个自定义形状添加到可观察集合中。
另一个选项是创建 Line[] 数组对象并将所有网格线添加到该数组中。
但我没能做到这一点。 有没有人可以在这个问题上指导我或给我不同的建议?
这些是 XAML 代码:
<Window x:Class="CanvasSampleMvvm.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:CanvasSampleMvvm.View"
xmlns:model="clr-namespace:CanvasSampleMvvm.Model"
xmlns:vm="clr-namespace:CanvasSampleMvvm.ViewModel"
mc:Ignorable="d"
Title="MainView" Height="450" Width="800">
<Window.Resources>
<vm:MainViewVM x:Key="vm"/>
</Window.Resources>
<Grid DataContext="{StaticResource vm}">
<ItemsControl ItemsSource="{Binding Path=Shapes}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type model:GridLines}">
<Line X1="{Binding From.X}" Y1="{Binding From.Y}"
X2="{Binding To.X}" Y2="{Binding To.Y}"
Stroke="{Binding Stroke}"
StrokeThickness="{Binding StrokeThickness}"
/>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas ClipToBounds="True" Background="Transparent" DataContext="{StaticResource vm}">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Window>
这些是 ViewModel 类代码:
public class MainViewVM : INotifyPropertyChanged
{
public ObservableCollection<GridLines> Shapes { get; } = new ObservableCollection<GridLines>();
public MainViewVM()
{
CreateGridLines();
}
private void CreateGridLines()
{
// draw lines
for (int x = -4000; x <= 4000; x += 100)
{
Shapes.Add(new GridLines
{
From = new Point(x, -4000),
To = new Point(x, 4000),
StrokeThickness = 1,
Stroke = new SolidColorBrush(Color.FromArgb(0xFF, 0x66, 0x66, 0x66)),
});
}
for (int y = -4000; y <= 4000; y += 100)
{
Shapes.Add(new GridLines
{
From = new Point(-4000, y),
To = new Point(4000, y),
StrokeThickness = 1,
Stroke = new SolidColorBrush(Color.FromArgb(0xFF, 0x66, 0x66, 0x66)),
});
}
}
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
这是模型类:
public class GridLines
{
public Point From { get; set; }
public Point To { get; set; }
public double Opacity { get; set; }
public Brush Stroke { get; set; }
public double StrokeThickness { get; set; }
}
您不得从视图模型中绘制视觉效果。视图模型仅管理数据呈现。如果需要进行一些手动绘图,请将代码移动到视图(代码隐藏)。
以下示例使用
Grid
绘制光栅。当您将 Grid.ShowGridLines
设置为 true
时,它会显示虚线分隔符。当您将栅格 Grid
和 Canvas
包装到公共 Grid
中时,您可以使用叠加(z 索引)。基本上,在光栅 Canvas
顶部绘制透明 Grid
。
这些示例使用 XAML,但您可以从代码隐藏动态生成栅格
Grid
。
以下示例绘制 6x6 光栅作为 200x200
Canvas
的背景。
使用内置网格线
Grid
:
<Grid Height="200"
Width="200">
<Grid.Resources>
<SolidColorBrush x:Key="CanvasBackgroundBrush"
Color="Yellow"
Opacity="0.3" />
</Grid.Resources>
<Grid ShowGridLines="True"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
<Canvas Background="{StaticResource CanvasBackgroundBrush}">
<Rectangle Width="50"
Height="50"
Canvas.Left="100"
Canvas.Top="100"
Fill="Orange" />
</Canvas>
</Grid>
将边框元素用于实体网格:
<Grid Height="200"
Width="200">
<Grid.Resources>
<SolidColorBrush x:Key="GridLinesBrush"
Color="Black"
Opacity="0.2" />
<Style TargetType="Border">
<Setter Property="BorderBrush"
Value="{StaticResource GridLinesBrush}" />
<Setter Property="BorderThickness"
Value="1" />
</Style>
<SolidColorBrush x:Key="CanvasBackgroundBrush"
Color="Yellow"
Opacity="0.3" />
</Grid.Resources>
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Grid.Row="0"
Grid.ColumnSpan="6" />
<Border Grid.Row="1"
Grid.ColumnSpan="6" />
<Border Grid.Row="2"
Grid.ColumnSpan="6" />
<Border Grid.Row="3"
Grid.ColumnSpan="6" />
<Border Grid.Row="4"
Grid.ColumnSpan="6" />
<Border Grid.Row="5"
Grid.ColumnSpan="6" />
<Border Grid.Column="0"
Grid.RowSpan="6" />
<Border Grid.Column="1"
Grid.RowSpan="6" />
<Border Grid.Column="2"
Grid.RowSpan="6" />
<Border Grid.Column="3"
Grid.RowSpan="6" />
<Border Grid.Column="4"
Grid.RowSpan="6" />
<Border Grid.Column="5"
Grid.RowSpan="6" />
</Grid>
<Canvas Background="{StaticResource CanvasBackgroundBrush}">
<Rectangle Width="50"
Height="50"
Canvas.Left="100"
Canvas.Top="100"
Fill="Orange" />
</Canvas>
</Grid>