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的使用介紹到這里,具體有疑問和不同看法歡迎與我溝通。