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。在特定条件下相同的命令需要执行不同的操作时,也可以更改执行函数来达到这种效果。