Command模式是设计模式中一个很重要也是十分好用的一个模式。
具体见Wiki : http://en.wikipedia.org/wiki/Command_pattern
SilverLight中定义了一个ICommand接口,该接口即为Command pattern的一个实现,接口定义如下:
可以由上图看出CanExecute方法中用来定义命令是否可被执行的逻辑。
这个接口和我们的项目密切相关,因为RelayCommand就是ICommand接口的一个具体实现。
目前在我们的项目中很多ViewModel中使用了RelayCommand 并通过binding的方式将UI的操作Binding到Command上面,
但多数ViewModel只是通过Command来封装操作,而忽略了ICommand接口提供的另一个方法:CanExecute
RelayCommand其实并非我们使用的那么简单,它内部有着另外一个被忽略的功能。
让我们看一下目前RenrenUI中定义的RelayCommand中的部分代码:
我们可以清楚的看到RelayCommand类就是ICommand接口的一个具体实现,而在Execute方法被调用的时候,会首先执行CanExecute方法。
我们再看一下RelayCommand的参数定义:
可以看到第二个参数为即为 Relaycommand内部 canExecute方法。
这将对我们ViewModel中Command的实现产生深远的影响。(目前执行函数中首先检查网络是否可用的函数随处可见)
让我们看一个具体的应用场景:
PoiDetailViewModel 在这个页面中取得详细信息的函数为如下声明:
这种写法在其他页面也十分常见,但此处存在一个问题,就是将CanExecute逻辑和Execute逻辑混淆在一起了,逻辑混淆意味着可维护性的降低,比如增加逻辑条件等。
同时也会导致存在大量判断是否可执行的重复代码。
我们应用前面说到的CanExecute对此进行重构:
在调用这个方法的时候,之前的方式为:
_poiDetailViewModel.GetPoiBaseInfoByPid();
封装成Command之后相应的改为:
_poiDetailViewModel.GetPoiBaseInfoByPidCommand.Execute(null);
但这种在页面后台代码中直接调用Command不推荐,应该用Binding方式实现。
修改完代码后,我们在CanXXX方法内加入断点可以看到,调用时CanXXX方法确实被执行:
总结:
虽然看上去写CanExecute方法需要增加一个方法的定义,但是如此实现更加灵活,比如检测网络和检测用户是否登录的操作可封装在一个CanExecute
方法里面。大大增加了开发和维护成本,并且使代码更加简洁,逻辑更加清晰。
MVVM架构不意味着简单的将原来后台代码挪到ViewModel中,对于这个UI架构我们应做更深的了解。
关于RelayCommand的使用介绍到这里,具体有疑问和不同看法欢迎与我沟通。