使用 MVVM / MVVMLight 时简单绘图应用程序的代码结构
Code structure for simple drawing apps when using MVVM / MVVMLight
我目前在我的一个应用程序中使用 MVVM
模式,更具体地说,我正在使用 MVVMLight
框架。在其中一个页面中,我将有一个屏幕,用户可以在其中输入 width
和 length
来绘制矩形,代码逻辑不多,所以我想将所有代码放在代码隐藏,因为此屏幕中发生的大部分内容都与 UI 相关。
在这种情况下使用代码隐藏是否有意义?如果不是,您将如何构建代码以使用 MVVM 模式,在这种情况下,您将在 ViewModel
中放入什么以及您将在代码后面放入什么?
这里是没有使用 MVVM 的代码。
XAML:
<Window x:Class="DrawingRectangles.MainWindow"
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:local="clr-namespace:DrawingRectangles"
mc:Ignorable="d"
Title="MainWindow" Height="531.798" Width="782.115">
<Grid Name="MyGrid" Width="480" Height="240" Margin="27,23,267,174">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="59*"/>
<ColumnDefinition Width="421*"/>
</Grid.ColumnDefinitions>
<Canvas Name="MyCanvas" Background="#FFF1F0F0" Margin="10" Grid.ColumnSpan="2"/>
<Grid Margin="10,235,10,-92" Background="WhiteSmoke" Grid.ColumnSpan="2">
<Button x:Name="drawButton" Content="Draw" Click="drawButton_Click"/>
<Button x:Name="resetButton" Content="Reset" Click="resetButton_Click"/>
<TextBox x:Name="textBoxPartWidth"/>
<TextBox x:Name="textBoxPartLength"/>
</Grid>
</Grid>
</Window>
代码隐藏:
namespace DrawingRectangles
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void drawButton_Click(object sender, RoutedEventArgs e)
{
clearScreen();
int xParts = 10;
int yParts = 10;
for (int i = 0; i < xParts; i++) {
for (int j = 0; j < yParts; j++) {
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = Convert.ToDouble(textBoxPartLength.Text);
myRectangle.Height = Convert.ToDouble(textBoxPartWidth.Text);
myRectangle.Margin = new Thickness((Convert.ToInt32(myRectangle.Width) + 1) * i, (Convert.ToInt32(myRectangle.Height) + 1) * j, 0, 0);
myRectangle.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
MyCanvas.Children.Add(myRectangle);
}
}
}
private void resetButton_Click(object sender, RoutedEventArgs e)
{
MyCanvas.Children.Clear();
}
private void clearScreen()
{
MyCanvas.Children.Clear();
}
}
}
UI
编辑:
第二张图(仅供参考):
视图中的 Button
应该绑定到视图模型的 ICommand
属性。单击 Button
时将执行该命令。有关如何在 MVVM 应用程序中处理事件的信息,请参阅 this blog post。在 MvvmLight 中,ICommand
实现被称为 RelayCommand
.
您还应该将 TextBoxes
的 Text
属性绑定到视图模型的两个源属性,并且视图中的 Canvas
元素应该替换为 ItemsControl
绑定到视图模型中定义的对象集合。
请参考下面的示例代码
型号:
public class Model
{
public int Width { get; set; }
public int Height { get; set; }
public Thickness Margin { get; set; }
public Brush Fill { get; set; }
}
查看:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="#FFF1F0F0" Margin="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}"
Height="{Binding Height}"
Margin="{Binding Margin}"
Fill="{Binding Fill}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Draw" Command="{Binding DrawCommand}" />
<Button Content="Reset" Command="{Binding ResetCommand}" />
<TextBox Text="{Binding Width}"/>
<TextBox Text="{Binding Height}"/>
查看模型:
public class ViewModel
{
public ViewModel()
{
DrawCommand = new RelayCommand(Draw);
ResetCommand = new RelayCommand(Clear);
}
public ObservableCollection<Model> Items { get; } = new ObservableCollection<Model>();
public RelayCommand DrawCommand { get; }
public RelayCommand ResetCommand { get; }
public int Width { get; set; }
public int Height { get; set; }
private void Draw()
{
Clear();
int xParts = 10;
int yParts = 10;
for (int i = 0; i < xParts; i++)
{
for (int j = 0; j < yParts; j++)
{
Model model = new Model();
model.Width = Width;
model.Height = Height;
model.Margin = new Thickness((model.Width + 1) * i, (model.Height + 1) * j, 0, 0);
model.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
Items.Add(model);
}
}
}
private void Clear()
{
Items.Clear();
}
}
在此示例中,所有应用程序逻辑都已移至它所属的视图模型。视图的代码隐藏 class 中没有任何逻辑。
另请注意,视图模型会创建 Model
个对象的实例,而不是创建 Rectangle
个元素。通常认为在视图模型 class 中引用 UI 元素是一种不好的做法。 Rectangle
元素由 ItemsControl
创建。查看视图中的 ItemTemplate
。
我目前在我的一个应用程序中使用 MVVM
模式,更具体地说,我正在使用 MVVMLight
框架。在其中一个页面中,我将有一个屏幕,用户可以在其中输入 width
和 length
来绘制矩形,代码逻辑不多,所以我想将所有代码放在代码隐藏,因为此屏幕中发生的大部分内容都与 UI 相关。
在这种情况下使用代码隐藏是否有意义?如果不是,您将如何构建代码以使用 MVVM 模式,在这种情况下,您将在 ViewModel
中放入什么以及您将在代码后面放入什么?
这里是没有使用 MVVM 的代码。
XAML:
<Window x:Class="DrawingRectangles.MainWindow"
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:local="clr-namespace:DrawingRectangles"
mc:Ignorable="d"
Title="MainWindow" Height="531.798" Width="782.115">
<Grid Name="MyGrid" Width="480" Height="240" Margin="27,23,267,174">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="59*"/>
<ColumnDefinition Width="421*"/>
</Grid.ColumnDefinitions>
<Canvas Name="MyCanvas" Background="#FFF1F0F0" Margin="10" Grid.ColumnSpan="2"/>
<Grid Margin="10,235,10,-92" Background="WhiteSmoke" Grid.ColumnSpan="2">
<Button x:Name="drawButton" Content="Draw" Click="drawButton_Click"/>
<Button x:Name="resetButton" Content="Reset" Click="resetButton_Click"/>
<TextBox x:Name="textBoxPartWidth"/>
<TextBox x:Name="textBoxPartLength"/>
</Grid>
</Grid>
</Window>
代码隐藏:
namespace DrawingRectangles
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void drawButton_Click(object sender, RoutedEventArgs e)
{
clearScreen();
int xParts = 10;
int yParts = 10;
for (int i = 0; i < xParts; i++) {
for (int j = 0; j < yParts; j++) {
// Create a rectangle.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = Convert.ToDouble(textBoxPartLength.Text);
myRectangle.Height = Convert.ToDouble(textBoxPartWidth.Text);
myRectangle.Margin = new Thickness((Convert.ToInt32(myRectangle.Width) + 1) * i, (Convert.ToInt32(myRectangle.Height) + 1) * j, 0, 0);
myRectangle.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
MyCanvas.Children.Add(myRectangle);
}
}
}
private void resetButton_Click(object sender, RoutedEventArgs e)
{
MyCanvas.Children.Clear();
}
private void clearScreen()
{
MyCanvas.Children.Clear();
}
}
}
UI
编辑:
第二张图(仅供参考):
视图中的 Button
应该绑定到视图模型的 ICommand
属性。单击 Button
时将执行该命令。有关如何在 MVVM 应用程序中处理事件的信息,请参阅 this blog post。在 MvvmLight 中,ICommand
实现被称为 RelayCommand
.
您还应该将 TextBoxes
的 Text
属性绑定到视图模型的两个源属性,并且视图中的 Canvas
元素应该替换为 ItemsControl
绑定到视图模型中定义的对象集合。
请参考下面的示例代码
型号:
public class Model
{
public int Width { get; set; }
public int Height { get; set; }
public Thickness Margin { get; set; }
public Brush Fill { get; set; }
}
查看:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="#FFF1F0F0" Margin="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}"
Height="{Binding Height}"
Margin="{Binding Margin}"
Fill="{Binding Fill}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Draw" Command="{Binding DrawCommand}" />
<Button Content="Reset" Command="{Binding ResetCommand}" />
<TextBox Text="{Binding Width}"/>
<TextBox Text="{Binding Height}"/>
查看模型:
public class ViewModel
{
public ViewModel()
{
DrawCommand = new RelayCommand(Draw);
ResetCommand = new RelayCommand(Clear);
}
public ObservableCollection<Model> Items { get; } = new ObservableCollection<Model>();
public RelayCommand DrawCommand { get; }
public RelayCommand ResetCommand { get; }
public int Width { get; set; }
public int Height { get; set; }
private void Draw()
{
Clear();
int xParts = 10;
int yParts = 10;
for (int i = 0; i < xParts; i++)
{
for (int j = 0; j < yParts; j++)
{
Model model = new Model();
model.Width = Width;
model.Height = Height;
model.Margin = new Thickness((model.Width + 1) * i, (model.Height + 1) * j, 0, 0);
model.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
Items.Add(model);
}
}
}
private void Clear()
{
Items.Clear();
}
}
在此示例中,所有应用程序逻辑都已移至它所属的视图模型。视图的代码隐藏 class 中没有任何逻辑。
另请注意,视图模型会创建 Model
个对象的实例,而不是创建 Rectangle
个元素。通常认为在视图模型 class 中引用 UI 元素是一种不好的做法。 Rectangle
元素由 ItemsControl
创建。查看视图中的 ItemTemplate
。