WPF - MVVM:如何用鼠标绘制一个可移动的矩形

WPF - MVVM: how to draw a movable Rectangle with mouse

我是 WPF 的新手,我想使用 MVVM 模式创建一个程序(不使用像 MvvmLight 这样的外部库)。该应用程序允许用户使用鼠标在 canvas 内绘制矩形(以及未来的其他形状)(类似于 Windows Paint,只是为了清楚起见)。用户也可以 move/resize 使用鼠标交互创建矩形。

此时我实现了一个基本版本,用户可以通过单击按钮添加一个矩形(随机 size/position)。这是实现此行为的 MainWindow 视图的代码:

    ...
    Title="{Binding Path=Titolo}"
    Height="450" Width="800"
    d:DataContext="{d:DesignInstance vm:MainWindowViewModel}">


<StackPanel>
    <StackPanel Orientation="Horizontal">
        <Button Content="Add Rectangle" Command="{Binding AddShapeCommand}" />
    </StackPanel>
    <Canvas>
        <ItemsControl ItemsSource="{Binding AllShapeCollection}">
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type vm:MyRectViewModel}">
                    <uc:MyRectView/>
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        

            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Canvas.Left" Value="{Binding xLT}"  />
                    <Setter Property="Canvas.Top" Value="{Binding yLT}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </Canvas>
</StackPanel>

用户控件MyRectView定义如下:

<UserControl x:Class="MVVM_TestRect.Views.MyRectView"
         ...
         xmlns:vm="clr-namespace:MVVM_TestRect.ViewModels"
         xmlns:local="clr-namespace:MVVM_TestRect.Views"
         mc:Ignorable="d" 
         d:DataContext="{d:DesignInstance vm:MyRectViewModel}"
         Width="auto" Height="auto">
   <Grid>
       <Rectangle Width="{Binding Path=Width, Mode=TwoWay}"
               Height="{Binding Path=Height, Mode=TwoWay}"
               Fill="Green"/>
   </Grid>
</UserControl>

程序按方面运行,绑定似乎没问题。

现在,如前所述,我将实现用鼠标绘图和 move/resize 形状的能力。 我找到了很多例子,但没有人能解决我的疑惑:

MVVM 模式只是将视觉设计与应用程序数据结构分开的理想模式,所以当您说“MVVM 模式不允许将事件处理程序(用于鼠标交互)放在视图代码隐藏中”时,也许就是这样太激烈了。尝试坚持它以获得更好的设计,但一开始不要太疯狂。看看 this page,它可能会引起您的兴趣。

WPF 在后面的代码中自动为您创建事件处理程序,因此这是它们的位置。您可能想要做的是,不是直接在事件处理程序中修改数据,而是会有一个 ViewModel,其方法将帮助您修改数据。

您可以使用与 Canvas 关联的 PreviewMouse(Up,Down,Move) 事件。这可能比尝试单击您的形状更容易,特别是当多个形状可能重叠时。显然,如果你有很多形状,必须有一种方法可以知道要编辑哪些形状(通过组合框手动选择,找到鼠标点击的闭合形状等)

从您的设计来看,可能会给您带来麻烦的一个方面是您的 viewModel 管理 1 个形状。这没有错,但您需要另一个管理形状集合的 VM 层。它可以作为另一个 class 或 MyRectViewModel:

中的一堆静态方法来完成

  void MyCanvas_PreviewMouseDown(object sender, MouseButtonEventArgs e)
  { 
       MyShapeCollectionViewModel.StoreMouseDown(e);
  }

  void MyCanvas_PreviewMouseMove(object sender, MouseButtonEventArgs e)
  { 
       MyShapeCollectionViewModel.ModifyShapes(e);
  }
    
  void MyCanvas_PreviewMouseUp(object sender, MouseButtonEventArgs e)
  { 
       MyShapeCollectionViewModel.ModifyShapes(e);
  }

其中ModifyShapes()将计算鼠标拖动,找到要编辑的形状并调用其编辑方法。然后,一旦修改了形状数据,就会触发相应的事件来更新关联的View