有了事件之后,为什么还需要命令呢?这个问题困扰了很久,直到我研究了设计模式里面的命令模式。
命令模式,就是把命令(或者说是控制逻辑抽象成一个对象),然后拆分出命令(Commadn),接收者(Recevicer),调用者(Invoker),具体命令(concretecommand),这样的好处就是降低了耦合,让程序变得更灵活,也就是设计模式的一个原则,对修改关闭,对扩展开放,当然对于大部分小项目来说,没有持续的升级迭代的,想改随意改,设计模式也没有什么用,,但是以我的经验,真的是非常有用。
回到WPF的命令中来,我们可以把他看作是WPF为我们具体实现了命令模式,给我们提供的语法糖,让我们可以更加快速地实现命令模式。
比如,我们一个页面上有好几个按钮,按钮1,按钮2,按钮3,按钮4,按钮5,如果按钮1对应干某件事情,这个事情没干完之前,按钮2,3,4,5的状态要是不可用,按钮2对应的事情1,3,4,5不可用,其他类似,那么我们当然可以在按钮对应的事件里面去修改button的状态,但是这样有个问题,就是如果按钮或者别的控件有很多,那么就很麻烦,这个时候我们可以把控件的状态和命令的状态保持同步,这样,几乎看不到后台有操作前台状态的代码,非常清晰。
WPF中的命令,主要记住以下三个东西就行了(暂时)。
Void Excute(object parameter),这个方法包含应用程序的逻辑处理,就是具体要干的事情。
Bool canexcute(object parameter),这个方法就是告诉程序命令的当前状态,如果可用就是True,反之则为False。
Canexcutechange事件,当命令状态发生改变时,引发这个事件,对于使用命令的控件,这是指示信号,表示应该调用canexcute方法检查命令的状态。通过这个事件,当命令可用时,命令源可启动自身,当命令不可用时,禁用自身。
首先我们实现一个内置的命令,最简单的
<Button Command="New" Content="Button" HorizontalAlignment="Left" Margin="148,136,0,0" VerticalAlignment="Top" Width="75"/>
按钮注册了一个New的命令,我们发现,按钮的状态自动变成灰色了,没有反应了,因为没有给命令具体实现
<Window.CommandBindings>
<CommandBinding Command="New" Executed="CommandBinding_Executed">
</CommandBinding>
</Window.CommandBindings>
写了一个Excuted事件的处理函数,这个时候就变得可用了,接下来,就是如果禁用命令。
<Grid>
<Button Command="New" Content="Button" HorizontalAlignment="Left" Margin="171,106,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="171,174,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
现在来用其中一个按钮的状态来控制另外一个按钮对应的命令的可以状态。
bool setCanExcute;
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = setCanExcute;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
setCanExcute = true;
}
很清晰就可以修改命令的状态了。
最后就是自定义命令,然后在应用程序执行过程中去调用,这个特别适合,我们封装好一个命令,然后在程序的N个地方调用,比如打印功能,应用程序正在打印的时候,又来了一个命令,那就不要执行了。
public class Class1
{
private static RoutedUICommand requery;
static Class1()
{
InputGestureCollection inputs = new InputGestureCollection();
inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, "Ctrl+R"));
requery = new RoutedUICommand("Requery", "Requery", typeof(Class1), inputs);
}
public static RoutedUICommand Requery
{
get { return requery; }
}
}
上面的代码就是定义了一个包含命令的类,包含一个静态属性,一个静态构造函数,和一个字段。
使用也很简单
<Window.CommandBindings>
<CommandBinding Command="my:Class1.requery" Executed="CommandBinding_Executed">
</CommandBinding>
</Window.CommandBindings>
把这个命令作为窗体的命令绑定进去,然后直接调用就行啦。
当然对于还有一些应用,是动态生成的控件,就需要使用代码去做命令绑定,逻辑是一样的,就是用代码实现。