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!");
}
