【问题标题】:Implement a Command Object that changes a property on my viewmodel实现一个命令对象来更改我的视图模型上的属性
【发布时间】:2016-07-20 19:34:40
【问题描述】:

我正在尝试学习 WPF/MVVM,出于教育原因,我创建了一个简单的应用程序。我在尝试实现 Command Object 时遇到了一些问题。

单击按钮控件时,我希望使用Command Object 将网格的背景颜色更改为黄色。关于如何做到这一点有很多东西,但我想用干净的方式来做。一般来说,我想在ViewViewModelCommand Object 之间实现松散耦合,以便测试这些类。

我也不想使用像 Prism 这样的库,因为我需要先完全理解 MVVM。

我有一个代码示例,但它当然没有功能。只是为了方便起见。

我对 XAML 的看法

<Window x:Class="Calendar.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:Calendar"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="480">

<Grid Background="{Binding BackgroundColour}" Margin="0,0,2,0">
    <Button Margin="197,247,200,-239" Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding SubmitCommand}">Color</Button>
</Grid>

我的模型视图类

public class MainWindowViewModel : INotifyPropertyChanged {

    //Command part
    ICommand SubmitCommand;
    public MainWindowViewModel(ICommand command) {
        SubmitCommand = command;
    }

    //Data Binding part
    public event PropertyChangedEventHandler PropertyChanged;
    private Brush backgroundColour = (Brush)new BrushConverter().ConvertFromString("Red");
    public Brush BackgroundColour {
        get { return this.backgroundColour; }
        set {
            if (value != this.backgroundColour) {
                this.backgroundColour = value;
                var handler = this.PropertyChanged;
                if (handler != null) {
                    handler(this, new PropertyChangedEventArgs("BackgroundColour"));
                }
            }
        }

(它也有数据绑定部分,但与我的问题无关)

【问题讨论】:

    标签: c# wpf xaml mvvm command


    【解决方案1】:

    您不希望在视图模型中包含任何与窗口相关的内容,例如颜色(画笔或画笔)。参考我下面的代码。

    <Window x:Class="MVVMNav_Learning.Window1"
        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:MVVMNav_Learning"
        mc:Ignorable="d"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:ColorConverterConverter x:Key="ColorConverterConverter"></local:ColorConverterConverter>
    </Window.Resources>
    <Grid>
        <Grid Background="{Binding BackgroundColour,Converter={StaticResource ColorConverterConverter}}" Margin="0,0,2,0">
            <Button Margin="50"  Command="{Binding SubmitCommand}">Color</Button>
        </Grid>
    </Grid>
    

     public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }
    }
    
    public class ViewModel:INotifyPropertyChanged
    {
        private MyColor backColor;
    
        public MyColor BackgroundColour
        {
            get { return backColor; }
            set { backColor = value; OnPropertyChanged("BackgroundColour"); }
        }
    
        public ICommand SubmitCommand { get; set; }
    
        public ViewModel()
        {
            BackgroundColour = MyColor.Red;
            SubmitCommand = new BaseCommand(Execute);
        }
    
        public void Execute(object parameter)
        {
            BackgroundColour = MyColor.Yellow;
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
    
    public enum MyColor
    {
        Red,
        Green,
        Yellow
    }
    
    public class BaseCommand : ICommand
    {
        private Action<object> _method;
        public event EventHandler CanExecuteChanged;
    
        public BaseCommand(Action<object> method)
        {
            _method = method;
        }
    
        public bool CanExecute(object parameter)
        {
            return true;
        }
    
        public void Execute(object parameter)
        {
            _method.Invoke(parameter);
        }
    }
    
    public class ColorConverterConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            MyColor color = (MyColor)value;
            switch (color)
            {
                case MyColor.Red:
                    return Brushes.Red;
                case MyColor.Green:
                    return Brushes.Green;
                case MyColor.Yellow:
                    return Brushes.Yellow;
                default:
                {
                    return Brushes.Red;
                }
            }
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    【讨论】:

    • Subeamanian 你提供的代码有很多东西,给我一些时间看看,我会回来提问。
    • SubmitCommand = new BaseCommand(Execute);这一行,它存在于ViewModel构造函数中,ViewModel如何知道Execute依赖?
    • 参考基本命令类,它是 ICommand 的常见实现,您不必使用单独的类来实现您的命令。假设在一个页面中,如果您有 5 个按钮,您不必创建 5 个类来处理点击逻辑,并且您也可以避免将视图模型信息传递给命令类。 BaseCommand 将有一个动作,它将在您的视图模型中调用一个方法。这是一种处理命令的巧妙方式。
    • 我可以在构造函数中使用 new 测试 ViewModel 类吗?
    • 是的,但是你需要改变BaseCommand的实现来处理CanExecute。
    【解决方案2】:

    您需要为ICommand SubmitCommand 创建一个公共属性,并且可以在其getter/setter 中使用私有DelegateCommand。

    【讨论】:

      【解决方案3】:

      你没有很清楚地说明你的问题,但我赌它是:如何为视图模型的构造函数配置命令参数以使其更改背景颜色?

      命令通过让它们实现ICommand.Execute(Object) 来完成它们的工作所以基本上你希望你传递给构造函数的命令对象有一个类似的方法:

      void Execute(object parameter)
          {
              viewModel.BackGroundColor=Brushes.Yellow;
          }
      

      这很尴尬:命令是从视图模型外部传递的,但它必须引用它才能更改其背景颜色。您可能需要重新考虑您的设计。

      此外:要让数据绑定引擎看到SubmitChangedCommand,它必须是一个属性:

      public ICommand SubmitChangesCommand {get;set;}
      

      【讨论】:

      • 好的,让我们用不同的形式再次提问。单击按钮时如何更改 Grid 背景颜色?
      • @dios231 按钮如何在单击时更改网格背景颜色使用命令
      • @dios231 所以:将问题添加到您的帖子中!
      猜你喜欢
      • 1970-01-01
      • 2011-07-04
      • 2014-10-06
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 2018-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多