![](https://img2018.cnblogs.com/blog/303905/201911/303905-20191127120135481-961096662.png)
在WPF的MVVM模式中,View和ViewModel之间数据和命令的关联都是通过绑定实现的,绑定后View和ViewModel并不产生直接的依赖。具体就是View中出现数据变化时会尝试修改绑定的目标。同样View执行命令时也会去寻找绑定的Command并执行。反过来,ViewModel在Property发生改变时会发个通知说“名字叫XXX的Property改变了,你们这些View中谁绑定了XXX也要跟着变啊!”,至于有没有View收到是不是做出变化也不关心。ViewModel中的Command脱离View就更简单了,因为Command在执行操作过程中操作数据时,根本不需要操作View中的数据,只需要操作ViewModel中的Property就可以了,Property的变化通过绑定就可以反映到View上。这样在测试Command时也不需要View的参与。这也是我在接触WPF初期时根本理解不了的所谓数据驱动。
这样一来ViewMode可以在完全没有View的情况下测试,View也可以在完全没有ViewModel的情况下测试(当然只是测试界面布局和动画等业务无关的内容)。
1、App中的代码:
public App()
{
CalculatorView view = new CalculatorView();
view.DataContext = new CalculatorViewModel();
view.Show();
}
|
2、Model层中CauculatorModel的代码
class CauculatorModel
{
public string FirstOperand { get ; set ; }
public string SecondOperand { get ; set ; }
public string Operation { get ; set ; }
public string Result { get ; set ; }
}
|
3、Command
public class DeletgateCommand<T>:ICommand
{
private readonly Action<T> _executeMethod = null ;
private readonly Func<T, bool > _canExecuteMethod = null ;
public DeletgateCommand(Action<T> executeMethod)
: this (executeMethod, null )
{ }
public DeletgateCommand(Action<T> executeMethod, Func<T, bool > canExecuteMethod)
{
if (executeMethod == null )
throw new ArgumentNullException( "executeMetnod" );
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
#region ICommand 成员
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T parameter)
{
if (_canExecuteMethod != null )
{
return _canExecuteMethod(parameter);
}
return true ;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T parameter)
{
if (_executeMethod != null )
{
_executeMethod(parameter);
}
}
#endregion
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
#region ICommand 成员
public bool CanExecute( object parameter)
{
if (parameter == null && typeof (T).IsValueType)
{
return (_canExecuteMethod == null );
}
return CanExecute((T)parameter);
}
public void Execute( object parameter)
{
Execute((T)parameter);
}
#endregion
}
|
4、ViewModwl层,为了简化,此处Add方法采用硬编码的形式
public class CalculatorViewModel
{
CauculatorModel calculatorModel;
private DeletgateCommand< string > addCommand;
public CalculatorViewModel()
{
calculatorModel = new CauculatorModel();
}
#region Public Properties
public string FirstOperand
{
get { return calculatorModel.FirstOperand; }
set { calculatorModel.FirstOperand = value; }
}
public string SecondOperand
{
get { return calculatorModel.SecondOperand; }
set { calculatorModel.SecondOperand = value; }
}
public string Operation
{
get { return calculatorModel.Operation; }
set { calculatorModel.Operation = value; }
}
public string Result
{
get { return calculatorModel.Result; }
set { calculatorModel.Result = value; }
}
#endregion
public ICommand AddCommand
{
get
{
if (addCommand == null )
{
addCommand = new DeletgateCommand< string >(Add, CanAdd);
}
return addCommand;
}
}
public void Add( string x)
{
FirstOperand = x;
SecondOperand = x;
Result = ( double .Parse(FirstOperand) + double .Parse(SecondOperand)).ToString();
Operation = "+" ;
MessageBox.Show( FirstOperand+ Operation +SecondOperand + "=" + Result);
}
private static bool CanAdd( string num)
{
return true ;
}
}
|
ViewModelBase中的代码:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null )
{
handler( this , new PropertyChangedEventArgs(propertyName));
}
}
}
|
5、View层
<Grid>
<TextBox Height= "23" Margin= "12,63,0,0" Name= "textBox1" VerticalAlignment= "Top" HorizontalAlignment= "Left" Width= "120" />
<Label Margin= "12,25,95,0" Name= "label2" Height= "32" VerticalAlignment= "Top" >请输入x的值! x+x=? </Label>
<Button Height= "23" Command= "{Binding AddCommand}"
CommandParameter= "{Binding ElementName=textBox1,Path=Text}" HorizontalAlignment= "Left" Margin= "12,102,0,0" Name= "button1" VerticalAlignment= "Top" Width= "75" >
确定</Button>
</Grid>
|
CommandParameter里传递的是一个参数,当然可以传递多个参数。