WPF之命令浅谈
?一、認識命令
1.1命令的特點
提到“命令”,我們應(yīng)該想到命令的發(fā)出者,命令的接受者,命令的內(nèi)容,準備工作,完成任務(wù),回報工作。。。與事件中的發(fā)送者,接受者,消息,處理,處理,處理一一對應(yīng),如果是單純的幾個對應(yīng)關(guān)系,的確用事件是能夠代替的,不過,命令相對事件有其自己的特點的。比如,古時候,如果兩個部落發(fā)動戰(zhàn)爭,經(jīng)常在出軍之前,做了充分的準備,才可能一聲令下,沖啊!相反,如果沒有準備好的話,一定會限制,軍隊不能隨意出軍,所以命令具有限制性。除此之外,命令一旦下達是不經(jīng)常更改的。如在軟件里面,一般Ctr+C命令是復(fù)制,沒有哪個軟件用這個命令表示粘貼的呢?所以說命令具有普遍性,除此之外,命令有自己的元素,這讓程序員定義命令的時間,有章可依,所以命令更具有規(guī)范性。上面的特點純屬個人理解,可能這些性質(zhì)不是非常嚴格。除此之外,很多網(wǎng)友對命令的使用褒貶不一,此文重在理解命令,所以上面特點僅供用于理解命令。
1.2WPF中命令的組成元素以及元素之間的關(guān)系
由上面的介紹,應(yīng)該可以猜出個大概了。下面直接給出其組成元素:
- 命令(Command)實現(xiàn)了ICommand接口的類,使用比較多的是RoutedCommand。
- 命令源(Command Source)命令的發(fā)送者,現(xiàn)實了ICommandSource接口的類,實現(xiàn)此類的元素主要有ButtonBase,Hyperlink,MenuItem、ListBoxItem等
- 命令目標(Command Target)命令的接受者,實現(xiàn)了IInputElement接口的類。
- 命令關(guān)聯(lián)(Command Binding)負責(zé)把外圍的邏輯與命令關(guān)聯(lián)起來。
相對事件的元素來說,命令元素之間的關(guān)系還是會復(fù)雜一些,具體的關(guān)系會通過命令的使用來說明。下面先簡單介紹一下自定義命令的步驟。?
a、創(chuàng)建命令類
如果命令沒有涉及到業(yè)務(wù)邏輯的話,一般使用WPF類庫的RoutedCommand類即可,如果要聲明相對邏輯復(fù)雜一些的類,可以實現(xiàn)RouteCommand類的繼承或者是ICommand的接口。
b、聲明命令實例
由于命令的普遍性,一般情況下程序中某類命令只需要一個命令實例即可(單件模式)。
c、指明命令的源
通常是可以點擊的控件,命令還有個好處就是,沒有準備好的命令,這個控件不可用。如果把命令看做炮彈,那么命令源相當(dāng)于火炮,這個火炮還是防走火的。
d、指明命令的目標
目標是命令的作用對象。如果指定了目標,無論是否有焦點,都會受到這個命令。如果沒有指定目標的話,擁有焦點的對象默認為命令目標。還有一個要注意的是設(shè)置目標是通過命名的源來設(shè)置的。格式為:命令源控件.CommandTarget = 目標控件;
? e、設(shè)置命令關(guān)聯(lián)
?關(guān)于設(shè)置命令關(guān)聯(lián)還是在實例中好好的體會一下吧。下面就通過一個例子來說明。
二、小試命令
? 下面的例子實現(xiàn)的是點擊按鈕時,清除文本框里面的內(nèi)容。由于代碼注釋寫的比較詳細,直接給代碼,然后具體再解釋:
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();//初始化命令I(lǐng)nitializeCommand();}//聲明并定義命令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));//為命令設(shè)置目標this.button1.CommandTarget = this.textBoxA;//創(chuàng)建命令關(guān)聯(lián)CommandBinding cb = new CommandBinding();//指定關(guān)聯(lián)的命令cb.Command = this.clearCmd;//確定此命令是否可以在其當(dāng)前狀態(tài)下執(zhí)行cb.CanExecute += cb_CanExecute;//調(diào)用此命令cb.Executed += cb_Executed;//把命令關(guān)聯(lián)到外圍控件上this.stackPanel.CommandBindings.Add(cb);}//執(zhí)行命令,要做的事情void cb_Executed(object sender, ExecutedRoutedEventArgs e){this.textBoxA.Clear();e.Handled = true;}//在執(zhí)行命令之前,檢查命令是否可以執(zhí)行對應(yīng)的處理器void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e){if (string.IsNullOrEmpty(this.textBoxA.Text)){e.CanExecute = false;}else{e.CanExecute = true;}e.Handled = true;}} }效果是:文本框沒有輸入內(nèi)容的話,按鈕是不可用的,當(dāng)文本框里面有文字的話,按鈕可用,點擊按鈕清除文本框內(nèi)容。效果如圖1:
圖1
? 通過效果圖,應(yīng)該基本上了解路由命令的,我在看書的時間,想起了一個問題,為什么叫路由命令,應(yīng)該是與路由事件有關(guān),后來又翻了一遍書,發(fā)現(xiàn)路由事件在下面圖中有提及到,在上面的代碼中,站在高處的元素StackPanel作為CommandBinding的載體(由于路由事件的傳播是在可視樹上傳播的,所以CommandBinding的載體一定為命令目標的外圍控件上面),CommandBinding來指定監(jiān)聽命令是否準備好的事件和命令的處理事件,然后告訴命令,由于命令源擁有命令的實例,命令源就會根據(jù)命令接到的信息,作出相應(yīng)的反應(yīng),在此處,命令只是捕捉信息和通知命令源,真正其作用的是CommandBinding指定的處理器。
???圖2
?三、WPF的命令庫
? 在WPF中微軟提供了一些便捷的命令庫:?ApplicationCommands、MediaCommands、ComponentCommands、NavigationCommands?和EditingCommands。下面通過一個例子來說明調(diào)用ApplicationCommands的Copy命令。點擊按鈕,把文本框內(nèi)容拷貝到另外一個文本框里面。?
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){//檢查是否能發(fā)出命令e.CanExecute = !string.IsNullOrEmpty(this.txt1.Text);e.Handled = false;}} }上面的例子是把Window作為CommandBinding的載體,而且是在XAML中實現(xiàn)的,注意與在后臺代碼上的區(qū)別,簡單的一個Copy功能就實現(xiàn)了。雖然說微軟提供了WPF類庫,但是處理函數(shù)還是要我們自己去寫的。還有一點要注意的是:可以用轉(zhuǎn)到定義查看ApplicationCommands類與其類里面的屬性,他們都是靜態(tài)的,所以都以單件模式出現(xiàn)。如果有兩個命令源,同使用一個“命令”,那么應(yīng)該怎么區(qū)別?原來命令源除了含有Command屬性,還含有CommandParmeter屬性,用來區(qū)分不同的命令源。在處理的時間,根據(jù)e.Parameter(如圖3)來獲取是哪個源發(fā)出的命令,來采取相應(yīng)的命令。關(guān)于其他的WPF類庫如果有用到的話再查msdn了。
圖3
?四、自定義命令
? 在小試命令的例子中,記錄了自定義RoutedCommand,路由命令中真正做事情的是CommandBinding。下面主要記錄一下自定義直接實現(xiàn)ICommand接口的命令。在介紹之前,先看一下ICommand接口的原型:
- event EventHandler CanExecuteChanged;
- bool CanExecute(object parameter);
- void Execute(object parameter);
其中第一個事件為,當(dāng)命令可執(zhí)行狀態(tài)發(fā)生改變時,可以激化此事件來通知其他對象。另外兩個方法在上面已經(jīng)用過同名的,在此不做重復(fù)說明。下面開始實現(xiàn)一個自定義直接實現(xiàn)ICommand接口的命令,同樣實現(xiàn)點擊源控件,清除目標控件的內(nèi)容:
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; }//重寫點擊處理函數(shù),注意由于事件的優(yōu)先級不同,如果命令源是button的話,下面的函數(shù)不起作用protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e){base.OnMouseLeftButtonDown(e);if (this.CommandTarget != null){this.Command.Execute(this.CommandTarget);}}}b.制作一個userControl控件。
XAML MiniView.csc.制作自定義命令界面。
<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();//下面的聲明命令方式,僅作為練習(xí)使用,由于命令//具有"全局性",所以一般聲明在靜態(tài)全局的地方,供全局使用ClearCommand clearCmd = new ClearCommand();this.ctrClear.Command = clearCmd;this.ctrClear.CommandTarget = this.miniView;}} }終于黏貼完了,弱弱的看一下效果吧!
?圖4
本例純屬筆記,但是涉及到的東西還是比較多的,包括接口、自定義控件以及命令的幾個組成元素,對于菜鳥的自己,如果細心的看幾遍還是能小有所獲的。
?五、總結(jié)
轉(zhuǎn)載于:https://www.cnblogs.com/dairuiqing/p/4189314.html
總結(jié)
- 上一篇: 关于java的JIT知识
- 下一篇: Python的数据处理学习(三)