WPF 手动实现 INotifyPropertyChanged 和 ICommand
查看 INotifyPropertyChanged 接口源码
namespace System.ComponentModel { // // 摘要: // Notifies clients that a property value has changed. public interface INotifyPropertyChanged { // // 摘要: // Occurs when a property value changes. event PropertyChangedEventHandler PropertyChanged; } }
INotifyPropertyChanged接口定义了一个属性改变处理事件,通知客户端这个属性值已经发生改变。
定义NotifyObject实现 INotifyPropertyChanged
public class NotifyObject : INotifyPropertyChanged { ////// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; ////// Checks if a property already matches a desired value. Sets the property and /// notifies listeners only when necessary. /// ////// /// /// /// protected virtual bool SetProperty (ref T storage,T value,[CallerMemberName] string propertyName=null) { if (EqualityComparer .Default.Equals(storage, value)) return false; storage = value; RaisePropertyChanged(propertyName); return true; } /// /// Raises this object's PropertyChanged event. /// /// protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
通过SetProperty
查看ICommand源码
namespace System.Windows.Input { // // 摘要: // Defines a command. public interface ICommand { // // 摘要: // Occurs when changes occur that affect whether or not the command should execute. event EventHandler CanExecuteChanged; // // 摘要: // Defines the method that determines whether the command can execute in its current // state. // // 参数: // parameter: // Data used by the command. If the command does not require data to be passed, // this object can be set to null. // // 返回结果: // true if this command can be executed; otherwise, false. bool CanExecute(object parameter); // // 摘要: // Defines the method to be called when the command is invoked. // // 参数: // parameter: // Data used by the command. If the command does not require data to be passed, // this object can be set to null. void Execute(object parameter); } }
ICommand接口定义了一个普通的事件,和命令执行方法Execute()、命令是否可以执行方法CanExecute()
定义DelegateCommand实现 ICommand
public class DelegateCommand : ICommand { public event EventHandler CanExecuteChanged; private readonly Action _executeMethod; private readonly Func_canExecuteMethod; /// /// Creates a new instance of DelegateCommand with the Action to invoke on execution. /// /// public DelegateCommand(Action executeMethod) : this(executeMethod, () => true) { } ////// Creates a new instance of DelegateCommand with the Action to invoke on execution /// and a Func to query for determining if the command can execute. /// /// /// public DelegateCommand(Action executeMethod, FunccanExecuteMethod) { if(executeMethod==null||canExecuteMethod==null) throw new ArgumentNullException(nameof(executeMethod)); _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; } /// /// Executes the command. /// /// public void Execute(object parameter) { _executeMethod(); } ////// Determines if the command can be executed. /// /// ///public bool CanExecute(object parameter) { return _canExecuteMethod(); } }
通过DelegateCommand构造函数加载两个委托(Action _executeMethod ,Func
在ViewModel中使用NotifyObject和DelegateCommand
public class MainWindowViewModel:NotifyObject { ////// 输入1 /// private double _input1; public double Input1 { get => _input1; set => SetProperty(ref _input1,value); } ////// 输入2 /// private double _input2; public double Input2 { get => _input2; set => SetProperty(ref _input2, value); } ////// 结果 /// private double _result; public double Result { get => _result; set => SetProperty(ref _result, value); } ////// 加法命令 /// public DelegateCommand _addCommand; public DelegateCommand AddCommand => _addCommand ??= new DelegateCommand(Add); private void Add() { Result = Input1+Input2; } }
在ViewModel 定义Input1 Input2 Result 跟View中的控件进行数据绑定,定义AddCommand跟View中事件拥有者绑定(命令绑定),当UI界面点击加法按钮,事件处理器就会响应这个命令执行Add()方法,完成运算。
总结:
通过上述接口实现,简单可以实现数据绑定和命令绑定,这个思路主要借鉴Prism框架,也是一个学习过程记录。