WPF MVVM 架构 Step By Step(6)(把actions从view model解耦)
到现在为止,我们创建了一个简单的MVVM的例子,包含了实现了的属性和命令。我们现在有这样一个包含了例如textbox类似的输入元素的视图,textbox用绑定来和view model联系,像点击button这样的行为用命令来联系。view model和model在内部通信。
但是在上面的架构中有一个问题,command类和view model有很严重的耦合。如果你记得command类的代码(在下面也有展示),在构造函数中传递view model对象,意味着这个command 类不能再其他的view model中重用。
public class ButtonCommand:ICommand { private CustomerViewModel _obj; public ButtonCommand(CustomerViewModel obj) { _obj = obj; } ...... ...... }
但是我们现在思考下什么是一个行为。它是一个来自于最终用户的像鼠标点击,按钮点击,菜单点击,按功能键等这样的事件。因此应该有一个方法去总结这些行为并且把他们用一个更通用的方式附加到view model里。
如果你认为逻辑行为是包含在方法和函数中的逻辑,那么什么是一个公用的方法去指向方法和函数呢?想想,那就是委托。
我们需要2个委托,一个用来CanExecute,另一个用来Execute。CanExecute返回一个布尔类型的值,因此用来验证,然后基于验证来允许和禁止用户接口。Execute当canexecute为真时执行。
public class ButtonCommand:ICommand { public bool CanExecute(object parameter) { //验证代码 } public void Execute(object parameter) { //执行逻辑 } }
换句话来说,我们需要2个委托,1个返回布尔值的函数其他一个action返回空。因此正好我们可以创建一个func和一个action。通过用委托的方式,我们试着来创建一个通用的类。在command类中我们做了如下3个改变:
- 我们把构造函数中移走view model的对象,输入变为2个委托,一个是Func一个是Action。Func用来验证,Action用来执行。2个委托的值都通过构造函数来传递再传给类的私有变量。
- Func 委托 = CanExecute
- Action 委托 = What To Execute
public class ButtonCommand:ICommand { private Action _whatToExecute; private Func<bool> _whenToExecute; public ButtonCommand(Action what,Func<bool> when ) { _whatToExecute = what; _whenToExecute = when; } public bool CanExecute(object parameter) { return _whenToExecute(); } public void Execute(object parameter) { _whatToExecute(); } public event EventHandler CanExecuteChanged; }
在model中,我们已经知道What to execute - CalculateTax,我们用了一个简单的函数(IsValid)用来验证customer类是否可用。
public class Customer { public void CalculateTax() { if (Amount > 2000) { _Tax = 20; } else if (Amount > 1000) { _Tax = 10; } else { _Tax = 5; } } public bool IsValid() { return Amount != 0; } }
在view model类,我们传递2个参数,一个Func,一个Action。
public class CustomerViewModel:INotifyPropertyChanged { private readonly ButtonCommand _objButtonCommandCommand; public CustomerViewModel() { _objButtonCommandCommand=new ButtonCommand(obj.CalculateTax,obj.IsValid); } public ICommand CalClick => _objButtonCommandCommand; private Customer obj = new Customer(); }
这让架构变得更好而且因为command类能用通用的方法和任何view model来结合使用而解耦。下面就是改善后的架构,注意现在view model怎么和command类通过委托来通信的。
PRISM是一个MVVM架构中不错的框架。PRISM主要的用处是用来模块化开发,它有一个不错的delegateCommand类,比我们自己创建自己的command类要好不少。
PRISM: http://www.microsoft.com/en-in/download/details.aspx?id=42537
WPF MVVM Step By Step 原文: http://www.codeproject.com/Articles/819294/WPF-MVVM-step-by-step-Basics-to-Advance-Level