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;
下面先看看一个命令方面的例子:
代码:
private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(MainWindow));
private void InitializeCommand()
{
this.button1.Command = clearCmd;
this.clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
this.button1.CommandTarget = this.textBoxA;
CommandBinding cb = new CommandBinding();
cb.Command = this.clearCmd;
cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExcecute);
cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
this.stackPanel.CommandBindings.Add(cb);
}
void cb_CanExcecute(object sender, CanExecuteRoutedEventArgs e)
{
if (string.IsNullOrEmpty(this.textBoxA.Text))
{
e.CanExecute = false;
}
else
{
e.CanExecute = true;
}
e.Handled = true;
}
void cb_Executed(object sender, ExecutedRoutedEventArgs e)
{
this.textBoxA.Clear();
e.Handled = true;
}
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附加事件。命令关联捕捉到后,就会执行一些任务了。
我们再来看看另外一个例子,我们自定义命令的例子:
/// <summary>
/// CustomRoutedCommand.xaml 的交互逻辑
/// </summary>
public partial class CustomRoutedCommand : UserControl,IView
{
public CustomRoutedCommand()
{
InitializeComponent();
} public bool IsChanged { get; set; }
public void SetBinding() { }
public void Refresh(){}
public void Save() { }
public void Clear()
{
this.textBox1.Clear();
this.textBox2.Clear();
this.textBox3.Clear();
this.textBox4.Clear();
}
} public interface IView
{
bool IsChanged { get; set; }
void SetBinding();
void Refresh();
void Clear();
void Save();
} public class ClearCommand : ICommand
{
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
} public event EventHandler CanExecuteChanged; public void Execute(object parameter)
{
IView view = parameter as IView;
if (view != null)
{
view.Clear();
}
//throw new NotImplementedException();
}
} public class MyCommandSource : UserControl, ICommandSource
{
public ICommand Command { get; set; }
public object CommandParameter { get; set; }
public IInputElement CommandTarget { get; set; } protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (CommandTarget != null)
{
this.Command.Execute(CommandTarget);
}
} }
也是点击一个按钮把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
WPF命令的更多相关文章
- WPF快速入门系列(5)——深入解析WPF命令
一.引言 WPF命令相对来说是一个崭新的概念,因为命令对于之前的WinForm根本没有实现这个概念,但是这并不影响我们学习WPF命令,因为设计模式中有命令模式,关于命令模式可以参考我设计模式的博文:h ...
- 八,WPF 命令
WPF命令模型 ICommand接口 WPF命令模型的核心是System.Windows.Input.ICommand接口,该接口定义了命令的工作原理,它包含了两个方法和一个事件: public in ...
- 【WPF学习】第三十一章 WPF命令模型
WPF命令模型由许多可变的部分组成.总之,它们都具有如下4个重要元素: 命令:命令表示应用程序任务,并且跟踪任务是否能够被执行.然而,命令实际上不包含执行应用程序任务的代码. 命令绑定:每个命令绑定针 ...
- WPF 命令基础
1命令的组成 命令源:就是谁发送的命令. 命令目标:就是这个命令发送给谁,谁接受的命令. 命令:就是命令的内容. 命令关联:就是把命令和外围的逻辑关联起来,主要用来判断命令是否可以执行和执行完以后干点 ...
- WPF 命令的简单总结
WPF的命令Command主要解决的问题,就是代码复用.一个很重要的应用意义,在于它将很多地方需要的调用的相同操作,以统一的方式管理,却又提供了不同的访问结果. 举个例子来说,我可能通过“点击butt ...
- WPF命令(Command)介绍、命令和数据绑定集成应用
要开始使用命令,必须做三件事: 一:定义一个命令 二:定义命令的实现 三:为命令创建一个触发器 WPF中命令系统的基础是一个相对简单的ICommand的接口,代码如下: public interfac ...
- WPF命令绑定 自定义命令
WPF的命令系统是wpf中新增加的内容,在以往的winfom中并没有.为什么要增加命令这一块内容.在winform里面的没有命令只使用事件的话也可以实现程序员希望实现的功能.这个问题在很多文章中都提到 ...
- WPF命令使用
What 命令包含以下部分: 命令:一个实现了ICommand接口的类,RoutedCommand是WPF里最常用的命令类,其它命令类大多派生自RoutedCommand 命令源:触发命令的对象,如b ...
- [转]WPF命令集 Command
在我们日常的应用程序操作中,经常要处理各种各样的命令和进行相关的事件处理,比如需要复制.粘贴文本框中的内容;上网查看网页时,可能需要返回上一网页查看相应内容;而当我们播放视频和多媒体时,我们可能要调节 ...
随机推荐
- myisam和innodb索引实现的不同
1.MyISAM 使用B+Tree 作为索引结构,叶子节点的data存放指针,也就是记录的地址.对于主键索引和辅助索引都是一样的.2.InnoDB 也使用B+Tree作为索引结构,也别需要注意的是,对 ...
- -_-#【jQuery】data
.data() <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...
- 数据结构:HDU 2993 MAX Average Problem
MAX Average Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- 【模拟】【数学】CSU 1803 2016 (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1803 题目大意: 给定n,m(n,m<=109)1<=i<=n,1& ...
- slf4j简介
SLF4J不是日志框架而是一个简单日志门面,它的目的是允许最终用户在部署时使用期望的日志框架. The Simple Logging Facade for Java (SLF4J) serves as ...
- [基础] C++与JAVA的内存管理
在内存管理上(总之一句话——以后C++工程,一定要用智能指针!) 1.同是new一个对象,C++一定得手动delete掉,而且得时刻记住能delete的最早时间(避免使用空指针).JAVA可以存活于作 ...
- 《A First Course in Probability》-chape6-随机变量的联合分布-基本概念
之前我们探讨了一元随机变量的分布列,下面我们应该将相应的性质推广到多元随机变量的分布列,在这里我们主要以讨论二元随机变量分布列为主. 利用类比的方法,我们很容易将一元随机变量的分布列的性质推广上来. ...
- Linus:为何对象引用计数必须是原子的
Linus大神又在rant了!这次的吐槽对象是时下很火热的并行技术(parellism),并直截了当地表示并行计算是浪费所有人时间(“The whole “let’s parallelize” thi ...
- 西安Uber优步司机奖励政策(1月18日~1月24日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- Seek the Name, Seek the Fame - POJ 2752(next运用)
题目大意:小猫是非常有名气的,所以很多父母都来找它给孩子取名字,因为找的人比较多,小猫为了摆脱这个无聊的工作,于是它发明了一种取名字的办法,它把孩子父母的名字合在一起,然后从这个名字里面找一个前缀,并 ...