通过使用 MVVM WPF 创建自定义形状将网格线添加到画布

问题描述 投票:0回答:1

我想将我的 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; }
    }
c# wpf canvas mvvm shapes
1个回答
0
投票

您不得从视图模型中绘制视觉效果。视图模型仅管理数据呈现。如果需要进行一些手动绘图,请将代码移动到视图(代码隐藏)。

以下示例使用

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>

© www.soinside.com 2019 - 2024. All rights reserved.