2.绑定命令,在WPF中,为了解决事件响应功能之间的耦合,提出了绑定命令思想,即命令可以绑定的方式与控件建立联系。绑定命令必须实现ICommand接口。
using System.ComponentModel; using System.Runtime.CompilerServices; namespace DemoMVVM.Core { /// <summary> /// 堆代码 duidaima.com /// 可被观测的类 /// </summary> public abstract class ObservableObject : INotifyPropertyChanged { /// <summary> /// 属性改变事件 /// </summary> public event PropertyChangedEventHandler? PropertyChanged; /// <summary> /// 属性改变触发方法 /// </summary> /// <param name="propertyName">属性名称</param> protected void RaisePropertyChanged([CallerMemberName]string propertyName=null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } /// <summary> /// 设置属性值,如果发生改变,则调用通知方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="target"></param> /// <param name="value"></param> /// <param name="propertyName"></param> /// <returns></returns> protected bool SetProperty<T>(ref T target,T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(target, value)) { return false; } else { target=value; RaisePropertyChanged(propertyName); return true; } } } }注意:上述SetProperty主要用于将普通属性,变为具备通知功能的属性。
namespace DemoMVVM.Core { /// <summary> /// ViewModel基类,继承自ObservableObject /// </summary> public abstract class ViewModelBase:ObservableObject { } }2. 具备绑定功能的命令
namespace DemoMVVM.Core { public class DelegateCommand : ICommand { private Action<object> execute; private Predicate<object> canExecute; public event EventHandler? CanExecuteChanged; public DelegateCommand(Action<object> execute, Predicate<object> canExecute) { if (execute == null) { throw new ArgumentNullException("execute 不能为空"); } this.execute = execute; this.canExecute = canExecute; } public DelegateCommand(Action<object> execute):this(execute,null) { } public bool CanExecute(object? parameter) { return canExecute?.Invoke(parameter)!=false; } public void Execute(object? parameter) { execute?.Invoke(parameter); } } }注意,DelegateCommand的构造函数,接收两个参数,一个是Execute(干活的),一个是CanExecute(判断是否可以干活的)。
using DemoMVVM.Core; using System; using System.Collections.Generic; using System.Linq; using System.Runtime; using System.Text; using System.Threading.Tasks; namespace DemoMVVM { public class MainWindowViewModel:ViewModelBase { #region 属性及构造函数 private double leftNumber; public double LeftNumber { get { return leftNumber; } set { SetProperty(ref leftNumber , value); } } private double rightNumber; public double RightNumber { get { return rightNumber; } set { SetProperty(ref rightNumber , value); } } private double resultNumber; public double ResultNumber { get { return resultNumber; } set { SetProperty(ref resultNumber , value); } } public MainWindowViewModel() { } #endregion #region 命令 private DelegateCommand operationCommand; public DelegateCommand OperationCommand { get { if (operationCommand == null) { operationCommand = new DelegateCommand(Operate); } return operationCommand; } } private void Operate(object obj) { if(obj == null) { return; } var type=obj.ToString(); switch (type) { case "+": this.ResultNumber = this.LeftNumber + this.RightNumber; break; case "-": this.ResultNumber = this.LeftNumber - this.RightNumber; break; case "*": this.ResultNumber = this.LeftNumber * this.RightNumber; break; case "/": if (this.RightNumber == 0) { this.ResultNumber = 0; } else { this.ResultNumber = this.LeftNumber / this.RightNumber; } break; } } #endregion } }创建视图,并在视图中进行数据绑定,将ViewModel和UI关联起来,如下所示:
<Window x:Class="DemoMVVM.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:DemoMVVM" mc:Ignorable="d" Title="MVVM示例" Height="350" Width="600"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition Width="0.3*"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal"> <TextBlock Text="A1:" VerticalAlignment="Center" ></TextBlock> <TextBox Margin="10" Width="120" Height="35" Text="{Binding LeftNumber, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center"></TextBox> </StackPanel> <StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal"> <TextBlock Text="A2:" VerticalAlignment="Center" ></TextBlock> <TextBox Margin="10" Width="120" Height="35" Text="{Binding RightNumber, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center"></TextBox> </StackPanel> <TextBlock Grid.Row="1" Grid.Column="2" Text="=" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock> <StackPanel Grid.Row="1" Grid.Column="3" Orientation="Horizontal"> <TextBlock Text="A3:" VerticalAlignment="Center" ></TextBlock> <TextBox Margin="10" Width="120" Height="35" Text="{Binding ResultNumber, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center"></TextBox> </StackPanel> <StackPanel Grid.Row="2" Grid.ColumnSpan="4" Orientation="Horizontal" HorizontalAlignment="Center"> <Button Content="+" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="+"></Button> <Button Content="-" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="-"></Button> <Button Content="*" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="*"></Button> <Button Content="/" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="/"></Button> </StackPanel> </Grid> </Window>注意,在xaml前端UI代码中,分别对TextBox的Text和Button的Command进行了绑定,已达到数据驱动UI,以及UI响应客户的功能。
namespace DemoMVVM { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private MainWindowViewModel viewModel; public MainWindow() { InitializeComponent(); viewModel = new MainWindowViewModel(); this.DataContext = viewModel; } } }
MVVM实例演示
通过以上步骤,已经完成了MVVM的简单应用。实例演示如下: