Mvvm中爲了實現UI和業務模塊的解耦,爲每個UI量身定製了一個ViewMoel,兩者的交互往往通過綁定進行,數據交互直接綁定數據即可,而業務交互則依靠命令綁定。命令綁定用到了設計模式中的命令模式,命令模式簡單的說就是將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可取消的操作。關於命令模式更多內容請點擊http://baike.baidu.com/view/1963264.htm#6.
Wp&Win8中命令模式是依靠ICommand接口實現的:
public interface ICommand
{
// 摘要:
// 當出現影響是否應執行該命令的更改時發生。
event EventHandler CanExecuteChanged;
// 摘要:
// 定義用於確定此命令是否可以在其當前狀態下執行的方法。
//
// 參數:
// parameter:
// 此命令使用的數據。如果此命令不需要傳遞數據,則該對象可以設置爲 null。
//
// 返回結果:
// 如果此命令可以執行,則爲 true;否則爲 false。
bool CanExecute(object parameter);
//
// 摘要:
// 定義在調用此命令時調用的方法。
//
// 參數:
// parameter:
// 此命令使用的數據。如果此命令不需要傳遞數據,則該對象可以設置爲 null。
void Execute(object parameter);
}
關於此接口的實現網上可以找到很多的示例,最初看到有人把每個命令都單獨封裝成了一個類,個人感覺這樣實現起來麻煩不說,而且靈活性也很差。後來找到了一種比較好的實現方法介紹給大家。
/// <summary>
///
/// </summary>
/// <typeparam name="T">執行函數的參數類型</typeparam>
public interface IActionCommand<T> : ICommand
{
/// <summary>
/// 設置執行函數
/// </summary>
/// <param name="action"></param>
void SetAction(Action<T> action);
/// <summary>
/// 設置確定此命令是否可以在其當前狀態下執行的方法
/// </summary>
/// <param name="canExecute"></param>
void SetCanExecute(Func<T, bool> canExecute);
/// <summary>
/// 執行函數改變時發生
/// </summary>
event EventHandler ActionChanged;
}
以上是命令模式通用接口,新增2個函數和一個事件。每個命令的執行方法和當前可執行方法都可以改變,改變時會觸發相應的事件。
以下是接口的具體實現:
public class ActionCommand<T> : IActionCommand<T>
{
private Action<T> _execute = obj => { };
private Func<T,bool> _canExecute = obj => true;
public event EventHandler CanExecuteChanged;
public event EventHandler ActionChanged;
public ActionCommand()
{
}
public ActionCommand(Action<T> execute)
{
_execute = execute;
}
public ActionCommand(Action<T> execute, Func<T, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public void SetAction(Action<T> action)
{
_execute = action;
var handler = ActionChanged;
if(handler!=null)
handler(this, EventArgs.Empty);
}
public void SetCanExecute(Func<T, bool> canExecute)
{
_canExecute = canExecute;
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
public bool CanExecute(object parameter)
{
return _canExecute((T) parameter);
}
public void Execute(object parameter)
{
if (CanExecute(parameter))
{
_execute((T) parameter);
}
}
}
使用如下:
public class ViewModel
{
public ActionCommand<object> FunCommand { get; private set; }
void Fun(object parameter)
{
}
public ViewModel()
{
InitializeData();
}
protected override void InitializeData()
{
FunCommand = new ActionCommand<object>(Fun);
}
}
在Xaml中使用如下:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetSourceCommand}" CommandParameter="123"/>
</i:EventTrigger>
</i:Interaction.Triggers>
一個ViewModel中可以有多個
Command。在特定條件下相同的命令需要執行不同的操作時,也可以更改執行函數來達到這種效果。