提到“命令”,咱们应该想到命令的发出者,命令的接受者,命令的内容,准备工做,完成任务,回报工做。。。与事件中的发送者,接受者,消息,处理,处理,处理一一对应,若是是单纯的几个对应关系,的确用事件是可以代替的,不过,命令相对事件有其本身的特色的。好比,古时候,若是两个部落发动战争,常常在出军以前,作了充分的准备,才可能一声令下,冲啊!相反,若是没有准备好的话,必定会限制,军队不能随意出军,因此命令具备限制性。除此以外,命令一旦下达是不常常更改的。如在软件里面,通常Ctr+C命令是复制,没有哪一个软件用这个命令表示粘贴的呢?因此说命令具备广泛性,除此以外,命令有本身的元素,这让程序员定义命令的时间,有章可依,因此命令更具备规范性。上面的特色纯属我的理解,可能这些性质不是很是严格。除此以外,不少网友对命令的使用褒贬不一,此文重在理解命令,因此上面特色仅供用于理解命令。程序员
由上面的介绍,应该能够猜出个大概了。下面直接给出其组成元素:windows
相对事件的元素来讲,命令元素之间的关系仍是会复杂一些,具体的关系会经过命令的使用来讲明。下面先简单介绍一下自定义命令的步骤。 app
a、建立命令类ide
若是命令没有涉及到业务逻辑的话,通常使用WPF类库的RoutedCommand类便可,若是要声明相对逻辑复杂一些的类,能够实现RouteCommand类的继承或者是ICommand的接口。函数
b、声明命令实例this
因为命令的广泛性,通常状况下程序中某类命令只须要一个命令实例便可(单件模式)。spa
c、指明命令的源code
一般是能够点击的控件,命令还有个好处就是,没有准备好的命令,这个控件不可用。若是把命令看作炮弹,那么命令源至关于火炮,这个火炮仍是防走火的。component
d、指明命令的目标xml
目标是命令的做用对象。若是指定了目标,不管是否有焦点,都会受到这个命令。若是没有指定目标的话,拥有焦点的对象默认为命令目标。还有一个要注意的是设置目标是经过命名的源来设置的。格式为:命令源控件.CommandTarget = 目标控件;
e、设置命令关联
关于设置命令关联仍是在实例中好好的体会一下吧。下面就经过一个例子来讲明。
下面的例子实现的是点击按钮时,清除文本框里面的内容。因为代码注释写的比较详细,直接给代码,而后具体再解释:
XAML代码:
<Window x:Class="Chapter_07.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="LightBlue" Title="MainWindow" Height="230" Width="260"> <StackPanel x:Name="stackPanel"> <Grid x:Name="grid" Margin="10"> <Button x:Name="button1" Content="Clear Commend" Height="50" Margin="0,10,0,440"/> <TextBox x:Name="textBoxA" Margin="0,65,0,325" /> </Grid> </StackPanel> </Window>
后台代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Chapter_07 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //初始化命令 InitializeCommand(); } //声明并定义命令 private RoutedCommand clearCmd = new RoutedCommand("Clear",typeof(MainWindow)); //初始化命令方法 private void InitializeCommand() { //把命令赋值给命令源,并指定快捷键 this.button1.Command = this.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 += cb_CanExecute; //调用此命令 cb.Executed += cb_Executed; //把命令关联到外围控件上 this.stackPanel.CommandBindings.Add(cb); } //执行命令,要作的事情 void cb_Executed(object sender, ExecutedRoutedEventArgs e) { this.textBoxA.Clear(); e.Handled = true; } //在执行命令以前,检查命令是否能够执行对应的处理器 void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e) { if (string.IsNullOrEmpty(this.textBoxA.Text)) { e.CanExecute = false; } else { e.CanExecute = true; } e.Handled = true; } } }
效果是:文本框没有输入内容的话,按钮是不可用的,当文本框里面有文字的话,按钮可用,点击按钮清除文本框内容。效果如图1:
图1
经过效果图,应该基本上了解路由命令的,我在看书的时间,想起了一个问题,为何叫路由命令,应该是与路由事件有关,后来又翻了一遍书,发现路由事件在下面图中有说起到,在上面的代码中,站在高处的元素StackPanel做为CommandBinding的载体(因为路由事件的传播是在可视树上传播的,因此CommandBinding的载体必定为命令目标的外围控件上面),CommandBinding来指定监听命令是否准备好的事件和命令的处理事件,而后告诉命令,因为命令源拥有命令的实例,命令源就会根据命令接到的信息,做出相应的反应,在此处,命令只是捕捉信息和通知命令源,真正其做用的是CommandBinding指定的处理器。
图2
在WPF中微软提供了一些便捷的命令库: ApplicationCommands、MediaCommands、ComponentCommands、NavigationCommands 和 EditingCommands。下面经过一个例子来讲明调用ApplicationCommands的Copy命令。点击按钮,把文本框内容拷贝到另一个文本框里面。
XAML代码以下:
<Window x:Class="Chapter_07.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" Background="Azure"> <StackPanel x:Name="stackpanel"> <TextBox x:Name="txt1" Margin="10" /> <TextBox x:Name="txt2" Margin="10" /> <Button x:Name="button1" Content="按钮一" Height="50" Margin="10" Command="ApplicationCommands.Copy"/> </StackPanel> <Window.CommandBindings> <CommandBinding Command="Copy" CanExecute="Copy_CanExecute" Executed="Copy_Executed"/> </Window.CommandBindings> </Window>
后台代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace Chapter_07 { /// <summary> /// Window1.xaml 的交互逻辑 /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Copy_Executed(object sender, ExecutedRoutedEventArgs e) { this.txt2.Text = this.txt1.Text; } private void Copy_CanExecute(object sender, CanExecuteRoutedEventArgs e) { //检查是否能发出命令 e.CanExecute = !string.IsNullOrEmpty(this.txt1.Text); e.Handled = false; } } }
上面的例子是把Window做为CommandBinding的载体,并且是在XAML中实现的,注意与在后台代码上的区别,简单的一个Copy功能就实现了。虽说微软提供了WPF类库,可是处理函数仍是要咱们本身去写的。还有一点要注意的是:能够用转到定义查看ApplicationCommands类与其类里面的属性,他们都是静态的,因此都以单件模式出现。若是有两个命令源,同使用一个“命令”,那么应该怎么区别?原来命令源除了含有Command属性,还含有CommandParmeter属性,用来区分不一样的命令源。在处理的时间,根据e.Parameter(如图3)来获取是哪一个源发出的命令,来采起相应的命令。关于其余的WPF类库若是有用到的话再查msdn了。
图3
在小试命令的例子中,记录了自定义RoutedCommand,路由命令中真正作事情的是CommandBinding。下面主要记录一下自定义直接实现ICommand接口的命令。在介绍以前,先看一下ICommand接口的原型:
其中第一个事件为,当命令可执行状态发生改变时,能够激化此事件来通知其余对象。另外两个方法在上面已经用过同名的,在此不作重复说明。下面开始实现一个自定义直接实现ICommand接口的命令,一样实现点击源控件,清除目标控件的内容:
a.准备工做:
//为了使目标控件,含有Clear()方法,因此在此一个定义接口 public interface IView { void Clear(); } //定义命令 public class ClearCommand : ICommand { public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { throw new System.NotImplementedException(); } public void Execute(object parameter) { IView view = parameter as IView; if (view != null) { view.Clear(); } } } //自定义命令源 public class MyCommandSource : System.Windows.Controls.UserControl, ICommandSource { public ICommand Command { get; set; } public object CommandParameter { get; set; } public IInputElement CommandTarget { get; set; } //重写点击处理函数,注意因为事件的优先级不一样,若是命令源是button的话,下面的函数不起做用 protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); if (this.CommandTarget != null) { this.Command.Execute(this.CommandTarget); } } }
b.制做一个userControl控件。
<UserControl x:Class="Chapter_07.MiniView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="140" Width="200"> <Border CornerRadius="5" BorderBrush="LawnGreen" BorderThickness="2" > <StackPanel > <TextBox x:Name="textBox1" Margin="5"/> <TextBox x:Name="textBox2" Margin="5"/> <TextBox x:Name="textBox3" Margin="5"/> <TextBox x:Name="textBox4" Margin="5"/> </StackPanel> </Border> </UserControl>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Chapter_07 { /// <summary> /// MiniView.xaml 的交互逻辑 /// </summary> public partial class MiniView : UserControl,IView { public MiniView() { InitializeComponent(); } public void Clear() { this.textBox1.Clear(); this.textBox2.Clear(); this.textBox3.Clear(); this.textBox4.Clear(); } } }
c.制做自定义命令界面。
<Window x:Class="Chapter_07.DefineCommand" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Chapter_07" Title="DefineCommand" Height="300" Width="300"> <StackPanel> <local:MyCommandSource x:Name="ctrClear" Margin="10"> <TextBlock Text="清除" FontSize="16" TextAlignment="Center" Background="LightGreen" Width="80"/> </local:MyCommandSource> <local:MiniView x:Name="miniView"/> </StackPanel> </Window>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace Chapter_07 { /// <summary> /// DefineCommand.xaml 的交互逻辑 /// </summary> public partial class DefineCommand : Window { public DefineCommand() { InitializeComponent(); //下面的声明命令方式,仅做为练习使用,因为命令 //具备"全局性",因此通常声明在静态全局的地方,供全局使用 ClearCommand clearCmd = new ClearCommand(); this.ctrClear.Command = clearCmd; this.ctrClear.CommandTarget = this.miniView; } } }
终于黏贴完了,弱弱的看一下效果吧!
图4
本例纯属笔记,可是涉及到的东西仍是比较多的,包括接口、自定义控件以及命令的几个组成元素,对于菜鸟的本身,若是细心的看几遍仍是能小有所获的。
本文主要经过简单的例子,认识了RoutedCommand和ICommand的自定义命令以及微软的WPF提供的命令库,虽然上面的例子比较简单,可是里面涉及的东西仍是颇有必要时常查阅的。本文是读书笔记,里面不免有理解不对的地方,欢迎讨论!下一篇:《深刻浅出WPF》笔记——资源篇。