【问题标题】:Code structure for simple drawing apps when using MVVM / MVVMLight使用 MVVM / MVVMLight 时简单绘图应用程序的代码结构
【发布时间】:2018-07-02 13:38:15
【问题描述】:

我目前在我的一个应用程序中使用MVVM 模式,更具体地说,我使用的是MVVMLight 框架。在其中一个页面中,我将有一个屏幕,用户可以在其中输入widthlength 来绘制矩形,没有太多代码逻辑,所以我想把我所有的代码放在代码隐藏中因为此屏幕中将发生的大部分内容都与 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();
        }
    }
}

用户界面

编辑: 第二张图片(仅供参考):

【问题讨论】:

  • 一般来说,在 MVVM 按钮单击 = 命令和文本字段 = 绑定到视图模型中的属性。您的目标是零代码,看来您的任务是可能的。
  • 可以开始here看看如何在mvvm中使用canvas。
  • 感谢两位提供的好信息。

标签: c# wpf mvvm mvvm-light


【解决方案1】:

视图中的Button 应该绑定到视图模型的ICommand 属性。当您单击Button 时,该命令将被执行。有关如何在 MVVM 应用程序中处理事件的信息,请参阅 this blog post。在 MvvmLight 中,ICommand 实现称为RelayCommand

您还应该将TextBoxesText 属性绑定到视图模型的两个源属性,并且视图中的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();
    }
}

在此示例中,所有应用程序逻辑都已移至其所属的视图模型。视图的代码隐藏类中没有任何逻辑。

还要注意,视图模型创建Model 对象的实例,而不是创建Rectangle 元素。通常认为在视图模型类中引用 UI 元素是一种不好的做法。 Rectangle 元素由ItemsControl 创建。查看视图中的ItemTemplate

【讨论】:

  • 当 SolidColorBrush 是 UI 元素时,您正在视图模型中创建多个 new SolidColorBrush(Color.FromArgb(170, 51, 51, 255))。这是一种不好的做法
  • 您链接过自己的博客吗?如果是,那么最好披露这一点。
  • 代码更正,Items.Add(myRectangle);应该是Items.Add(model);
  • @fs_tigre:已修复。
  • @fs_tigre:如果您还有其他问题,请提出新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-23
  • 2011-06-04
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 2015-05-20
相关资源
最近更新 更多