提到「命令」,咱們應該想到命令的發出者,命令的接受者,命令的內容,準備工做,完成任務,回報工做。。。與事件中的發送者,接受者,消息,處理,處理,處理一一對應,若是是單純的幾個對應關係,的確用事件是可以代替的,不過,命令相對事件有其本身的特色的。好比,古時候,若是兩個部落發動戰爭,常常在出軍以前,作了充分的準備,纔可能一聲令下,衝啊!相反,若是沒有準備好的話,必定會限制,軍隊不能隨意出軍,因此命令具備限制性。除此以外,命令一旦下達是不常常更改的。如在軟件裏面,通常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》筆記——資源篇。