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, Func canExecuteMethod)
{
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框架,也是一个学习过程记录。