namespace System.ComponentModel { // // 摘要: // Notifies clients that a property value has changed. public interface INotifyPropertyChanged { // // 摘要: // Occurs when a property value changes. event PropertyChangedEventHandler PropertyChanged; } }
INotifyPropertyChanged接口定義了一個屬性改變處理事件,通知客戶端這個屬性值已經發生改變。框架
public class NotifyObject : INotifyPropertyChanged { /// <summary> /// Occurs when a property value changes. /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Checks if a property already matches a desired value. Sets the property and /// notifies listeners only when necessary. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="storage"></param> /// <param name="value"></param> /// <param name="propertyName"></param> /// <returns></returns> protected virtual bool SetProperty<T>(ref T storage,T value,[CallerMemberName] string propertyName=null) { if (EqualityComparer<T>.Default.Equals(storage, value)) return false; storage = value; RaisePropertyChanged(propertyName); return true; } /// <summary> /// Raises this object's PropertyChanged event. /// </summary> /// <param name="propertyName"></param> protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
經過SetProperty<T>泛型方法 能夠接收任意類型的屬性,而後判斷屬性值是否發生變化,若是變化就觸發PropertyChanged事件,通知UI本屬性值已經發生改變。函數
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()學習
public class DelegateCommand : ICommand { public event EventHandler CanExecuteChanged; private readonly Action _executeMethod; private readonly Func<bool> _canExecuteMethod; /// <summary> /// Creates a new instance of DelegateCommand with the Action to invoke on execution. /// </summary> /// <param name="executeMethod"></param> public DelegateCommand(Action executeMethod) : this(executeMethod, () => true) { } /// <summary> /// 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. /// </summary> /// <param name="executeMethod"></param> /// <param name="canExecuteMethod"></param> public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod) { if(executeMethod==null||canExecuteMethod==null) throw new ArgumentNullException(nameof(executeMethod)); _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; } /// <summary> /// Executes the command. /// </summary> /// <param name="parameter"></param> public void Execute(object parameter) { _executeMethod(); } /// <summary> /// Determines if the command can be executed. /// </summary> /// <param name="parameter"></param> /// <returns></returns> public bool CanExecute(object parameter) { return _canExecuteMethod(); } }
經過DelegateCommand構造函數加載兩個委託(Action _executeMethod ,Func<bool> _canExecuteMethod),若是存在能夠正常實現命令,這裏ICommand的實現也是極簡模式,後面能夠繼續擴展。ui
public class MainWindowViewModel:NotifyObject { /// <summary> /// 輸入1 /// </summary> private double _input1; public double Input1 { get => _input1; set => SetProperty(ref _input1,value); } /// <summary> /// 輸入2 /// </summary> private double _input2; public double Input2 { get => _input2; set => SetProperty(ref _input2, value); } /// <summary> /// 結果 /// </summary> private double _result; public double Result { get => _result; set => SetProperty(ref _result, value); } /// <summary> /// 加法命令 /// </summary> 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()方法,完成運算。this
總結:spa
經過上述接口實現,簡單能夠實現數據綁定和命令綁定,這個思路主要借鑑Prism框架,也是一個學習過程記錄。blog