实现一个命令对象来更改视图模型上的属性

本文关键字:视图 模型 属性 对象 命令 一个 实现 | 更新日期: 2023-09-27 17:57:59

我正在尝试学习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>

我的ModelView类

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"));
                }
            }
        }

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

实现一个命令对象来更改视图模型上的属性

您不希望在视图模型中有任何与窗口相关的内容,如颜色(画笔或笔刷)。请参阅我的以下代码。

<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();
    }
}

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

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

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

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

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

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

public ICommand SubmitChangesCommand {get;set;}