WPF命令

WPF的命令是经常使用的,在MVVM中,RelayCommand更是用得非常多,但是命令的本质究竟是什么,有了事件为什么还要命令,命令与事件的区别是什么呢?MVVM里面是如何包装命令的呢?命令为什么能够触发呢?带着这些疑问,我们深入讲解下命令:

首先看看命令系统的几个基本元素:

1) 命令(Command):实现了ICommand接口的类,用得最多的是RoutedCommand.

  ICommand的成员:

  event EventHandler CanExecuteChanged;

  bool CanExecute(object parameter);确定此命令能否执行的方法

  void Execute(object parameter);执行命令调用的方法

2) 命令源(Command Source):即命令的发送者,是实现了ICommandSource接口的类,很多界面元素都实现了这个接口,其中包括Button, MenuItem, ListBoxItem等。

  ICommandSource成员:

         ICommand Command{get;}   获取将在调用命令源时执行的命令

    object CommandParameter{get; } 命令参数。

IInputElement CommandTarget{get;} 将在其上执行命令的对象。

3)命令目标(Command Target):即命令讲发送给谁,或者说命令将作用在谁身上。命令目标必须是实现了IInputElement接口的类。

4)命令关联(Command Binding):负责把一些外围逻辑与命令关联起来,比如执行之前对命令是否可以执行进行判断、命令执行之后还有哪些后续工作。

  CommandBinding的成员:

    public ICommand Command{get; set;} 与这个CommandBinding关联的ICommand。

   public event CanExecuteRoutedEventHandler CanExecute;

public event ExecutedRoutedEventHandler Executed;

public event CanExecuteRoutedEventHandler PreviewCanExecute;

public event ExecuteRoutedEventHandler PreviewExecuted;

下面先看看一个命令方面的例子:

代码:

 1   private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(MainWindow));
 2         private void InitializeCommand()
 3         {
 4             this.button1.Command = clearCmd;
 5             this.clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
 6             this.button1.CommandTarget = this.textBoxA;
 7
 8             CommandBinding cb = new CommandBinding();
 9             cb.Command = this.clearCmd;
10             cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExcecute);
11             cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
12
13             this.stackPanel.CommandBindings.Add(cb);
14
15         }
16
17         void cb_CanExcecute(object sender, CanExecuteRoutedEventArgs e)
18         {
19             if (string.IsNullOrEmpty(this.textBoxA.Text))
20             {
21                 e.CanExecute = false;
22             }
23             else
24             {
25                 e.CanExecute = true;
26             }
27             e.Handled = true;
28         }
29
30         void cb_Executed(object sender, ExecutedRoutedEventArgs e)
31         {
32             this.textBoxA.Clear();
33             e.Handled = true;
34         }

UI上一个按钮,一个文本框,上级UI是StackPanel。
实现的功能是当文本框里面没有内容的时候,按钮是不是能的,当有内容的时候,按钮使能。

我们来对照着命令的几大要素,来分析下这个例子:

首先一个clearCmd的路由命令,RoutedCommand,实现了ICommand接口。

然后就是命令源,这里是Button,它实现了ICommandSource接口,在这里把clearCmd路由命令赋值给了其成员Command,把文本框赋值给了命令的目标。

然后命令目标就是文本框,实现了IInputElement接口

最后就是CommandBinding,这里给StackPanel的CommandBindings赋值,其中CommandBinding的Command赋值为clearCmd,并且定义两个事件驱动程序,用来处理CanExecute,Execute。

另外还有快捷键的设置方式,这不是重点,我们重点看看命令的执行模式到底如何?工作原理是什么?

通过调查,我发现是这样的:

首先命令源会一直查询其Command,如果有就执行命令,然后就连接到了命令目标,命令目标激发路由事件,然后在外围的控件的CommandBinding监控下捕捉相关的路由事件,然后就会调用相关的事件处理程序。

对应这个例子,是这样的,button作为命令源,赋值了clearCmd命令,然后通过查询并执行这个命令,命令连接到命令目标文本框,然后文本框激发出路由事件clearCmd,然后安装在StackPanel的CommandBinding监控下,如果是找到的命令的能否执行命令,就执行能否执行命令的事件处理函数,这里的能否执行返回的值直接决定了命令源是否可用。如果找到的命令式执行命令,就执行执行命令的处理函数,这里执行就把文本框清空。为了提高效率,一般都要e.Handled = True.

我们可以看出,真正起作用的是CommandBinding,命令源的目的是告诉命令目标发了命令,还有让命令目标激光路由事件,命令目标的目的就是发生路由事件,CommandBinding赋值监听命令,执行命令。

用通俗的话说,命令源就相当于火炮,命令相当于炮弹,命令目标相当于跑到要打的目标,命令关联就详单与侦察兵,在打炮弹之前的观察敌情,以及打扫战场等事情。

命令源会不断的像命令目标投石问路,命令目标就会不断的发送路由事件PreviewCanExcecute和CanExcecute附加事件,命令被发送出来并达到命令目标,命令目标就会发送PreviewExecuted和Executed附加事件。命令关联捕捉到后,就会执行一些任务了。

我们再来看看另外一个例子,我们自定义命令的例子:

 1   /// <summary>
 2     /// CustomRoutedCommand.xaml 的交互逻辑
 3     /// </summary>
 4     public partial class CustomRoutedCommand : UserControl,IView
 5     {
 6         public CustomRoutedCommand()
 7         {
 8             InitializeComponent();
 9         }
10
11         public bool IsChanged { get; set; }
12         public void SetBinding() { }
13         public void Refresh(){}
14         public void Save() { }
15         public void Clear()
16         {
17             this.textBox1.Clear();
18             this.textBox2.Clear();
19             this.textBox3.Clear();
20             this.textBox4.Clear();
21         }
22     }
23
24     public interface IView
25     {
26         bool IsChanged { get; set; }
27         void SetBinding();
28         void Refresh();
29         void Clear();
30         void Save();
31     }
32
33     public class ClearCommand : ICommand
34     {
35         public bool CanExecute(object parameter)
36         {
37             throw new NotImplementedException();
38         }
39
40         public event EventHandler CanExecuteChanged;
41
42         public void Execute(object parameter)
43         {
44             IView view = parameter as IView;
45             if (view != null)
46             {
47                 view.Clear();
48             }
49             //throw new NotImplementedException();
50         }
51     }
52
53     public class MyCommandSource : UserControl, ICommandSource
54     {
55         public ICommand Command { get; set; }
56         public object CommandParameter { get; set; }
57         public IInputElement CommandTarget { get; set; }
58
59         protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
60         {
61             base.OnMouseLeftButtonDown(e);
62             if (CommandTarget != null)
63             {
64                 this.Command.Execute(CommandTarget);
65             }
66         }
67
68     }

也是点击一个按钮把4个文本框全部清空。
同样的我们来分析下各个要素:

命令:ClearCommand, 实现了ICommand接口,这里的命令执行方法,是执行命令参数的清除方法。

命令源:MyCommandSource,这是一个用户控件,实现了ICommandSource接口,左键按钮里面如果有命令目标,就执行命令方法。

命令目标是一个窗体,他实现了IView接口,接口里面有个清除方法。

这里没有CommandBinding。实际执行的代码就是命令目标的IView接口的方法。

当我们点击按钮的时候,触发了命令的执行,命令执行调用IView接口的方法。

这个自定义的过程要比上面那个例子要好理解一点。

上面的那个例子存在命令源,路由命令和CommandBinding三者之间的关系,命令并不真正执行逻辑代码,是靠CommandBinding来实现逻辑的,当我们真正自定义的命令的时候,如果想简单的使用命令,我们可以把逻辑放到命令里面去,这样便于管理,以上的自定义命令的例子就是这样。

至于MVVM里面的RelayCommand命令,一样也是实现的ICommand接口。当我们把命令通过binding赋值给命令源的Command后,当命令源的命令触发的时候,就执行RelayCommand的方法,这个方法是一个委托方法,这样我们就可以通过Binding来把联系了控件和控件要执行的行为。

命令跟事件可能否是在一起被触发的,比如在ButtonBase的OnClick方法里面是这样的:

protected virtual void OnClick()
{
        RoutedEventArgs e = new RoutedEventArgs(ButtonBase.ClickEvent, this);
       base.RaiseEvent(e);
       CommandHelpers.ExecuteCommandSource(this);
}

可以看出在Click里面,先激发路由事件,再执行命令。

总结:对于命令而言,我们说的几大要素,命令,命令源,命令目标,命令关联,在路由命令中,一般都是存在的,命令在命令源的激发下,到命令目标,有可能没有命令目标,通过命令关联来监控并执行逻辑方面的事情。但是我们一般使用比如MVVM里面的RelayCommand,一般逻辑代码都是放在命令里面的,一般没有命令目标及命令关联。

到目前为止,虽然大致对命令有了个了解,但是对于WPF预定义的一些命令没有完全理解,以及对于命令的好处也没有完全理解,以后随着使用越来越多,再去总结吧。

http://files.cnblogs.com/files/monkeyZhong/RoutedCommandEg.zip

时间: 2024-12-26 18:45:42

WPF命令的相关文章

【转载wpf命令】

出处:http://blog.csdn.net/fwj380891124 WPF学习之深入浅出话命令 分类:             WPF              2012-11-05 18:08     4934人阅读     评论(2)     收藏     举报 WPF为我们准备了完善的命令系统,你可能会问:“有了路由事件为什么还需要命令系统呢?”.事件的作用是发布.传播一些消息,消息传达到了接收者,事件的指令也就算完成了,至于如何响应事件送来的消息事件并不做任何限制,每个接收者可已用

WPF快速入门系列(5)——深入解析WPF命令

一.引言 WPF命令相对来说是一个崭新的概念,因为命令对于之前的WinForm根本没有实现这个概念,但是这并不影响我们学习WPF命令,因为设计模式中有命令模式,关于命令模式可以参考我设计模式的博文:http://www.cnblogs.com/zhili/p/CommandPattern.html.命令模式的要旨在于把命令的发送者与命令的执行者之间的依赖关系分割开了.对此,WPF中的命令也是一样的,WPF命令使得命令源(即命令发送者,也称调用程序)和命令目标(即命令执行者,也称处理程序)分离.现

八,WPF 命令

WPF命令模型 ICommand接口 WPF命令模型的核心是System.Windows.Input.ICommand接口,该接口定义了命令的工作原理,它包含了两个方法和一个事件: public interface ICommand { void Execute(object parameter); //定义在调用此命令时调用的方法. bool CanExecute(object parameter); //此方法返回命令的状态,如果命令可用则返回true,否则返回false. event Ev

(WPF)命令

WPF里已经有了路由事件,为什么还需要命令呢? 因为事件的作用是发布.传播一些消息,消息到达接收者,事件的指令就算完成.至于如何响应事件的消息机智 只负责发送消息,对消息如何处理没有约束.而命令是有约束力的.命令除了可以约束代码,还可以约束步骤逻辑. 如Save命令:先做校验,再保存,最后退出. 命令系统的基本元素: 命令(Command):WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的就是RoutedCommand类. 命令源(Command Source):即命令的发送

【WPF学习】第三十一章 WPF命令模型

原文:[WPF学习]第三十一章 WPF命令模型 WPF命令模型由许多可变的部分组成.总之,它们都具有如下4个重要元素: 命令:命令表示应用程序任务,并且跟踪任务是否能够被执行.然而,命令实际上不包含执行应用程序任务的代码. 命令绑定:每个命令绑定针对用户界面的具体区域,将命令连接到相关的应用程序逻辑.这种分解的设计是非常重要的,因为单个命令可用于应用程序中的多个地方,并且在每个地方具有不同的意义.为处理这一问题,需要将同一命令与不同的命令绑定. 命令源:命令源触发命令.例如,MenuItem和B

WPF命令绑定 自定义命令

WPF的命令系统是wpf中新增加的内容,在以往的winfom中并没有.为什么要增加命令这一块内容.在winform里面的没有命令只使用事件的话也可以实现程序员希望实现的功能.这个问题在很多文章中都提到了.但大家都是引用深入浅出wpf里面的概述.没有用自己的话来阐述.当然你仔细理解一下的话也很容易理解.但在这里我还是用我自己的话来说一下什么情况下使用命令. 命令具有约束力 事件的... http://v.17173.com/playlist_23735679.htmlhttp://v.17173.

WPF命令(Command)介绍、命令和数据绑定集成应用

要开始使用命令,必须做三件事: 一:定义一个命令 二:定义命令的实现 三:为命令创建一个触发器 WPF中命令系统的基础是一个相对简单的ICommand的接口,代码如下: public interface ICommand { event EventHandler CanExecuteChanged; bool CanExecute(object parameter); void Execute(object parameter); } CanExecute用于确定命令是否处于可执行的状态.典型的

WPF命令参数CommandParameter

XAML代码如下: <Window x:Class="Demo006.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="240" Wi

WPF C# 命令 学习

1.概述 1.1 WPF C# 命令的本质 命令是 WPF 中的输入机制,它提供的输入处理比设备输入具有更高的语义级别. 例如,在许多应用程序中都能找到的“复制”.“剪切”和“粘贴”操作就是命令. WPF 中的命令是通过实现 ICommand 接口创建的. ICommand 的 WPF 实现是 RoutedCommand 类,这是WPF C# 命令的本质. 1.2 WPF C# 命令的机制 1.2.1 编程范围 ICommand 公开两个方法(Execute 及 CanExecute)和一个事件