实现一个命令对象来更改视图模型上的属性
本文关键字:视图 模型 属性 对象 命令 一个 实现 | 更新日期: 2023-09-27 17:57:59
我正在尝试学习WPF/MVVM,出于教育原因,我创建了一个简单的应用程序。我在尝试实现Command Object
时遇到了一些问题。
单击按钮控件时,我希望使用Command Object
将网格的背景颜色更改为黄色。关于如何做到这一点,有很多东西,但我想用干净的方式来做。通常,我想在View
、ViewModel
和Command 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;}