1.DelegateCommand
2.RelayCommand
3.AttachbehaviorCommand
因為MVVM模式適合於WPF和SL,所以這3種模式中也有一些小差異,比如RelayCommand下面的CommandManager方法就是WPF下面的,SL下面無法使用,不過我認為這3種方法中的基本思路都如出一轍,都是出自那位外國牛人的文章裡面。主要的區別在於和VIEW中的控制元件的繫結使用上。有點不同的attachbehaviorcommand是prism4裡面的一種設計模式,這個區別有點大。但我自己覺得最方便的還是這個DelegateCommand。
DelegateCommand
/// <summary> /// Delegatecommand,這種WPF.SL都可以用,VIEW裡面直接使用INTERACTION的trigger激發。比較靠譜,適合不同的UIElement控制元件 /// </summary> public class DelegateCommand : ICommand { Func<object, bool> canExecute; Action<object> executeAction; bool canExecuteCache; public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute) { this.executeAction = executeAction; this.canExecute = canExecute; } #region ICommand Members public bool CanExecute(object parameter) { bool temp = canExecute(parameter); if (canExecuteCache != temp) { canExecuteCache = temp; if (CanExecuteChanged != null) { CanExecuteChanged(this, new EventArgs()); } } return canExecuteCache; } public event EventHandler CanExecuteChanged; public void Execute(object parameter) { executeAction(parameter); } #endregion }
這個類大概可以這樣來理解,建構函式中的action和func,action負責判斷是否執行這個command,action就是觸發這個command之後要執行的方法。這樣理解最淺顯,但對剛熟悉command的我來講,這樣最方便記憶和學習,為了使用ICommand介面實現的方法和事件的解釋搜搜就可以找到,但是剛開始理解起來還是有點晦澀。
下面是VM裡面用這個command的例子。繫結了一個button控制元件,最簡單例子。cm1Click就是建構函式裡面的fuc,負責執行響應事件的方法。Cancm1Click就是建構函式裡面的action,負責判斷這個Command的響應事件是否執行,這裡沒有用到判斷式,直接賦了一個true.
public class TestViewModels:INotifyPropertyChanged { public TestViewModels() { ...... cm1click = new DelegateCommand(cm1Click,Cancm1Click); //初始化delegatecommand } .... //DelegateCommand #region command1 public ICommand cm1click { get; set; } public void cm1Click(object param) { MessageBox.Show("CM1 clicked!"); } private bool Cancm1Click(object param) { return true; } #endregion command1 ...... }
在XAML裡面,用interaction來繫結這個事件,而不是在button裡面用command來繫結,這樣做有個好處,就是非常直觀,並且可以響應其他的很多事件
<Button x:Name="BTN_CM1" Content="DelegateCommand" Height="115" Width="148" > <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <i:InvokeCommandAction Command="{Binding cm1click}"/> </i:EventTrigger> </i:Interaction.Triggers> </Button>
RelayCommand
RelayCommand本來是WPF下面用的一種自定義的command,主要是它用到了事件管理函式,這個SL下面是沒有的。不過這部分程式碼如果修改一下,也可以在SL下面使用,和WPF下面的實現思路差不多。
先看下RelayCommand的定義,一共有2種。
public class RelayCommand<T> : ICommand { public RelayCommand(Action<T> execute) : this(execute, null) { } public RelayCommand(Action<T> execute, Predicate<T> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute((T)parameter); } public event EventHandler CanExecuteChanged { add{} remove{} //add //{ // if (_canExecute != null) // CommandManager.RequerySuggested += value; //} //remove //{ // if (_canExecute != null) // CommandManager.RequerySuggested -= value; //} } public void Execute(object parameter) { _execute((T)parameter); } readonly Action<T> _execute = null; readonly Predicate<T> _canExecute = null; bool ICommand.CanExecute(object parameter) { throw new NotImplementedException(); } event EventHandler ICommand.CanExecuteChanged { add { throw new NotImplementedException(); } remove { throw new NotImplementedException(); } } void ICommand.Execute(object parameter) { throw new NotImplementedException(); } }
第一種是採用泛型的Relaycommand定義
public class RelayCommand : ICommand { public RelayCommand(Action execute) : this(execute, null) { } public RelayCommand(Action execute, Func<bool> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(); } public event EventHandler CanExecuteChanged { //這裡把實現註釋掉了,這樣在SL下面也可以用。 add { } remove { } //add //{ // if (_canExecute != null) // CommandManager.RequerySuggested += value; //} //remove //{ // if (_canExecute != null) // CommandManager.RequerySuggested -= value; //} } public void Execute(object parameter) { _execute(); } readonly Action _execute; readonly Func<bool> _canExecute; }
第二種就是最常用的定義,可以看到在CanExecuteChanged事件裡面把commmandmanager方法給註釋掉了,就可以在SL下面使用這個類,而且現在看好像也沒有什麼問題。
在程式碼上看,Relaycommand和delegatcommand基本上沒有啥區別,也是實現了func和action兩個引數的辦法,基本思路一樣。
它們最大的區別就是在前端的呼叫方式上。delegatecommand使用了expression的SDK裡面的interaction來繫結事件,而這種就是直接通過buttonbase的command屬性來繫結,因此只能執行單擊事件,所以使用範圍比較侷限,不過如果用interaction來繫結事件的話,其實實現就和delegatecommand一樣了。不過為了總結下學習,還是分開來區別下。
前端XAML的程式碼
<Button x:Name="BTN_CM2" Content="Command2" Height="103" HorizontalAlignment="Left" Margin="115,123,0,0" VerticalAlignment="Top" Width="109" Command="{Binding command2}" />
後臺
private ICommand _command2; public ICommand command2 { get { if (this._command2 == null) { this._command2 = new RelayCommand( () => this.cm2Click(), () => this.Cancm2Click); } return this._command2; } set { } } public bool Cancm2Click { get { return true; } } public void cm2Click() { MessageBox.Show("CM2 Clicked!"); }
原文地址: http://www.cnblogs.com/matoo/archive/2012/04/14/2447159.html
http://www.cnblogs.com/matoo/archive/2012/04/17/2452987.html