WPF之命令浅谈
?一、認識命令
1.1命令的特點
提到“命令”,我們應該想到命令的發出者,命令的接受者,命令的內容,準備工作,完成任務,回報工作。。。與事件中的發送者,接受者,消息,處理,處理,處理一一對應,如果是單純的幾個對應關系,的確用事件是能夠代替的,不過,命令相對事件有其自己的特點的。比如,古時候,如果兩個部落發動戰爭,經常在出軍之前,做了充分的準備,才可能一聲令下,沖啊!相反,如果沒有準備好的話,一定會限制,軍隊不能隨意出軍,所以命令具有限制性。除此之外,命令一旦下達是不經常更改的。如在軟件里面,一般Ctr+C命令是復制,沒有哪個軟件用這個命令表示粘貼的呢?所以說命令具有普遍性,除此之外,命令有自己的元素,這讓程序員定義命令的時間,有章可依,所以命令更具有規范性。上面的特點純屬個人理解,可能這些性質不是非常嚴格。除此之外,很多網友對命令的使用褒貶不一,此文重在理解命令,所以上面特點僅供用于理解命令。
1.2WPF中命令的組成元素以及元素之間的關系
由上面的介紹,應該可以猜出個大概了。下面直接給出其組成元素:
- 命令(Command)實現了ICommand接口的類,使用比較多的是RoutedCommand。
- 命令源(Command Source)命令的發送者,現實了ICommandSource接口的類,實現此類的元素主要有ButtonBase,Hyperlink,MenuItem、ListBoxItem等
- 命令目標(Command Target)命令的接受者,實現了IInputElement接口的類。
- 命令關聯(Command Binding)負責把外圍的邏輯與命令關聯起來。
相對事件的元素來說,命令元素之間的關系還是會復雜一些,具體的關系會通過命令的使用來說明。下面先簡單介紹一下自定義命令的步驟。?
a、創建命令類
如果命令沒有涉及到業務邏輯的話,一般使用WPF類庫的RoutedCommand類即可,如果要聲明相對邏輯復雜一些的類,可以實現RouteCommand類的繼承或者是ICommand的接口。
b、聲明命令實例
由于命令的普遍性,一般情況下程序中某類命令只需要一個命令實例即可(單件模式)。
c、指明命令的源
通常是可以點擊的控件,命令還有個好處就是,沒有準備好的命令,這個控件不可用。如果把命令看做炮彈,那么命令源相當于火炮,這個火炮還是防走火的。
d、指明命令的目標
目標是命令的作用對象。如果指定了目標,無論是否有焦點,都會受到這個命令。如果沒有指定目標的話,擁有焦點的對象默認為命令目標。還有一個要注意的是設置目標是通過命名的源來設置的。格式為:命令源控件.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的命令庫
? 在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接口的原型:
- event EventHandler CanExecuteChanged;
- bool CanExecute(object parameter);
- void Execute(object parameter);
其中第一個事件為,當命令可執行狀態發生改變時,可以激化此事件來通知其他對象。另外兩個方法在上面已經用過同名的,在此不做重復說明。下面開始實現一個自定義直接實現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控件。
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();//下面的聲明命令方式,僅作為練習使用,由于命令//具有"全局性",所以一般聲明在靜態全局的地方,供全局使用ClearCommand clearCmd = new ClearCommand();this.ctrClear.Command = clearCmd;this.ctrClear.CommandTarget = this.miniView;}} }終于黏貼完了,弱弱的看一下效果吧!
?圖4
本例純屬筆記,但是涉及到的東西還是比較多的,包括接口、自定義控件以及命令的幾個組成元素,對于菜鳥的自己,如果細心的看幾遍還是能小有所獲的。
?五、總結
轉載于:https://www.cnblogs.com/dairuiqing/p/4189314.html
總結
- 上一篇: 关于java的JIT知识
- 下一篇: 构建ASP.NET MVC4+EF5+E