一、WPF为何需要命令

我们已经知道WPF里已经有了路由事件,可以发布及传播一些消息,那为什么还需要命令呢?这是因为事件指负责发送消息,对消息如何处理则不管,而命令是有约束力,每个接收者对命令执行统一的行为,比如菜单上的保存,工具栏上的保存都必须是执行同样的保存。

二、命令系统的基本元素

命令(Command):实现了ICommand接口的类,经常使用的有RoutedCommand类

命令源: 是命令的发送者,是实现了ICommandSource接口的类,大部分界面的控件都实现了这个接口,Button, MenuItem 等等。

命令目标:命令的接收者,命令目标是视线了IInputElement接口的类。

命令关联:负责一些逻辑与命令关联起来,比如判断命令是否可以执行,以及执行完毕后做一些处理。

三、四个命令元素之间的关系

WPF-命令_内置

四、命令示例

我们让一个按钮发送Hello命令给文本框,文本框接收这个命令后显示“Nice to meet you”.




​view source​​​​print​​​​?​



​01​

​<​​​Window​ ​​x:Class​​​​=​​​​"DeepXAML.MainWindow"​


​02​

​xmlns​​​​=​​​​"http://schemas.microsoft.com/winfx/2006/xaml/presentation"​


​03​

​xmlns:x​​​​=​​​​"http://schemas.microsoft.com/winfx/2006/xaml"​


​04​

​xmlns:local​​​​=​​​​"clr-namespace:DeepXAML"​​       


​05​

​xmlns:sys​​​​=​​​​"clr-namespace:System;assembly=mscorlib"​


​06​

​Title​​​​=​​​​"MainWindow"​​ ​​Height​​​​=​​​​"250"​​ ​​Width​​​​=​​​​"450"​​​​> ​


​07​

 


​08​

​<​​​StackPanel​ ​​x:Name​​​​=​​​​"stackPanel"​​​​> ​


​09​

​<​​​TextBox​ ​​x:Name​​​​=​​​​"textBox1"​​ ​​Margin​​​​=​​​​"10"​​​​></​​​TextBox​​​> ​


​10​

​<​​​TextBox​ ​​x:Name​​​​=​​​​"textBox2"​​ ​​Margin​​​​=​​​​"10"​​​​></​​​TextBox​​​> ​


​11​

​<​​​Button​ ​​x:Name​​​​=​​​​"btnHello"​​ ​​Margin​​​​=​​​​"10"​​​​>Hello</​​​Button​​​> ​


​12​

​</​​​StackPanel​​​> ​


​13​

​</​​​Window​​​>​


 

后台代码




​view source​​​​print​​​​?​



​01​

using​ ​​System; ​


​02​

using​ ​​System.Collections.Generic; ​


​03​

using​ ​​System.Windows; ​


​04​

using​ ​​System.Windows.Data; ​


​05​

using​ ​​System.Windows.Documents; ​


​06​

using​ ​​System.Windows.Controls; ​


​07​

using​ ​​System.Windows.Input; ​


​08​

 


​09​

namespace​ ​​DeepXAML ​


​10​

​{ ​


​11​

public​ ​partial​ ​class​ ​​MainWindow : Window ​


​12​

​{ ​


​13​

private​ ​​RoutedCommand helloCmd = ​​​new​ ​​RoutedCommand(​​​​"Hello"​​​​, ​​​typeof​​​(MainWindow)); ​


​14​

 


​15​

public​ ​​MainWindow() ​


​16​

​{ ​


​17​

​InitializeComponent(); ​


​18​

 


​19​

this​​​.btnHello.Command = ​​​this​​​.helloCmd; ​


​20​

this​​​.helloCmd.InputGestures.Add(​​​new​ ​​KeyGesture(Key.H, ModifierKeys.Alt)); ​


​21​

this​​​.btnHello.CommandTarget = ​​​this​​​.textBox1; ​


​22​

this​​​.btnHello.CommandTarget = ​​​this​​​.textBox2; ​


​23​

 


​24​

​CommandBinding cb = ​​​new​ ​​CommandBinding(); ​


​25​

​cb.Command = ​​​this​​​.helloCmd; ​


​26​

​cb.CanExecute += ​​​new​ ​​CanExecuteRoutedEventHandler(cb_CanExecute); ​


​27​

​cb.Executed += ​​​new​ ​​ExecutedRoutedEventHandler(cb_Executed); ​


​28​

 


​29​

this​​​.stackPanel.CommandBindings.Add(cb); ​


​30​

​} ​


​31​

 


​32​

void​ ​​cb_Executed(​​​object​ ​​sender, ExecutedRoutedEventArgs e) ​


​33​

​{             ​


​34​

this​​​.textBox1.Text = ​​​​"Nice to meet you"​​​​; ​


​35​

this​​​.textBox2.Text = ​​​​"Nice to meet you"​​​​; ​


​36​

​e.Handled = ​​​true​​​; ​


​37​

 


​38​

​} ​


​39​

 


​40​

void​ ​​cb_CanExecute(​​​object​ ​​sender, CanExecuteRoutedEventArgs e) ​


​41​

​{ ​


​42​

if​ ​​(!​​​string​​​.IsNullOrEmpty(textBox1.Text) || !​​​string​​​.IsNullOrEmpty(textBox2.Text)) ​


​43​

​{ ​


​44​

​e.CanExecute=​​​false​​​; ​


​45​

​} ​


​46​

else


​47​

​{ ​


​48​

​e.CanExecute = ​​​true​​​; ​


​49​

​} ​


​50​

 


​51​

​// 避免继续传递 ​


​52​

​e.Handled = ​​​true​​​;             ​


​53​

​} ​


​54​

​} ​


​55​

​}​


 

执行时

一开始按钮状态可用,也就是命令可执行

WPF-命令_WPF_02

点击按钮后:

WPF-命令_内置_03

清空一个TextBox,按钮仍然不可执行,因为没达到可执行的条件,两个都清空时,按钮重回可执行状态

 

 

五、WPF的命令库

WPF提供常用应用程序所用的命令集,常用的命令集包括:ApplicationCommands, ComponentCommands, NavigationCommands, MediaCommands和EditingCommands。 ApplicationCommands(应用程序命令): CancelPrint:取消打印 Close:关闭 ContextMenu:上下文菜单 Copy:复制 CorrectionList: Gets the value that represents the Correction List command. Cut:剪切 Delete:删除 Find:查找 Help:帮助 New:新建 NotACommand:不是命令,被忽略 Open:打开 Paste:粘贴 Print:打印 PrintPreview:打印预览 Properties:属性 Redo:重做 Replace:取代 Save:保存 SaveAs:另存为 SelectAll:选择所有的 Stop:停止 Undo:撤消 ComponentCommands(组件命令): ExtendSelection:后接Down/Left/Right/Up, 比如:ExtendSelectionDown(Shift+Down,Extend Selection Down),ExtendSelectionLeft等 Move:后接Down/Left/Right/Up, 如:MoveDown MoveFocus:后接Down/Forward/Back/Up, 如:MoveFocusDown MoveFocusPage:后接Down/Up,如:MoveFocusPageUp MoveTo:后接End/Home/PageDown/PageUp,比如:MoveToPageDown ScrollByLine ScrollPage:后接Down/Left/Right/Up,比如:ScrollPageLeft SelectTo:End/Home/PageDown/PageUp,比如:SelectToEnd NavigationCommands(导航命令): Browse浏览: 后接Back/Forward/Home/Stop, 比如:BrowseBack 缩放显示:DecreaseZoom, IncreaseZoom, Zoom Favorites(收藏) 页面:FirstPage, LastPage, PreviousPage, NextPage,GoToPage NavigateJournal Refresh(刷新) Search(搜索) MediaCommands(多媒体控制命令): Treble高音:DecreaseTreble,IncreaseTreble Bass低音:BoostBass,DecreaseBass,IncreaseBass Channel频道:ChannelDown,ChannelUp MicrophoneVolume麦克风音量调节:DecreaseMicrophoneVolume,IncreaseMicrophoneVolume,MuteMicrophoneVolume ToggleMicrophoneOnOff:麦克风开关 Volume音量: DecreaseVolume,IncreaseVolume,MuteVolume Rewind, FastForward(回放,快进) Track轨道:PreviousTrack,NextTrack [上一段(节)] Play,Pause,Stop,Record(播放,暂停,停止,录制) TogglePlayPause Select选择 EditingCommands(编辑/排版类命令): Align对齐:AlignCenter,AlignJustify,AlignLeft,AlignRight(居中,撑满,左对齐,右对齐) Backspace退格 TabForward,TabBackward(Tab前缩,Tab向后) FontSize字体大小:DecreaseFontSize,IncreaseFontSize Indentation缩排:DecreaseIndentation, IncreaseIndentation Delete删除: Delete选中部分,DeleteNextWord:删除后一字,DeletePreviousWord:删除前一字 EnterLineBreak:换行 EnterParagraphBreak:换段 CorrectSpellingError/IgnoreSpellingError:纠正/忽略拼写错误 MoveUpByLine,MoveDownByLine: 上/下移一行, MoveUpByPage,MoveDownByPage: 上/下移一页 MoveUpByParagraph,MoveDownByParagraph: 上/下移一段 MoveLeftByCharacter/MoveRightByCharacter:左/右移一字符 MoveLeftByWord/MoveRightByWord 左/右移一词 MoveToDocumentStart/MoveToDocumentEnd:到文章开头/结尾 MoveToLineStart/MoveToLineEnd:到一行的开头/结尾 SelectUpByLine,SelectDownByLine:向上/下选一行 SelectUpByPage,SelectDownByPage:向上/下选一页 SelectUpByParagraph,SelectDownByParagraph:向上/下选一段 SelectLeftByCharacter,SelectRightByCharacter:向左/右选中一字 SelectLeftByWord,SelectRightByWord:向左/右选中一词 SelectToDocumentStart,SelectToDocumentEnd: 选中到篇头/篇尾 SelectToLineStart/SelectToLineEnd:选中到行首/行尾 ToggleBold, ToggleItalic, ToggleUnderline(加粗,斜体,下划线) ToggleBullets, ToggleNumbering(列表:加点,加数字) ToggleInsert:插入 ToggleSuperscript,ToggleSubscript(上标字,下标字)

 

六、命令参数

命令大部分都是类的静态属性,也就是示例只有一个,那么如果两个按钮使用同一个命令如何区分呢?比如新建一个Project,如何区分新建的是Library还是WPF呢?我们可以使用CommandParameter

XAML:




​view source​​​​print​​​​?​



​01​

​<​​​Window​ ​​x:Class​​​​=​​​​"DeepXAML.MainWindow"​


​02​

​xmlns​​​​=​​​​"http://schemas.microsoft.com/winfx/2006/xaml/presentation"​


​03​

​xmlns:x​​​​=​​​​"http://schemas.microsoft.com/winfx/2006/xaml"​


​04​

​xmlns:local​​​​=​​​​"clr-namespace:DeepXAML"​​       


​05​

​xmlns:sys​​​​=​​​​"clr-namespace:System;assembly=mscorlib"​


​06​

​Title​​​​=​​​​"MainWindow"​​ ​​Height​​​​=​​​​"250"​​ ​​Width​​​​=​​​​"450"​​​​> ​


​07​

​<​​​Window.CommandBindings​​​> ​


​08​

​<​​​CommandBinding​ ​​Command​​​​=​​​​"New"​​ ​​CanExecute​​​​=​​​​"New_CanExecute"​​ ​​Executed​​​​=​​​​"New_Executed"​​​​></​​​CommandBinding​​​> ​


​09​

​</​​​Window.CommandBindings​​​> ​


​10​

​<​​​StackPanel​ ​​x:Name​​​​=​​​​"stackPanel"​​​​>         ​


​11​

​<​​​TextBox​ ​​x:Name​​​​=​​​​"textBox"​​ ​​Margin​​​​=​​​​"10"​​​​></​​​TextBox​​​> ​


​12​

​<​​​Button​ ​​x:Name​​​​=​​​​"btnWPF"​​ ​​Margin​​​​=​​​​"10"​​ ​​Command​​​​=​​​​"New"​​ ​​CommandParameter​​​​=​​​​"WPF"​​​​>新建WPF</​​​Button​​​> ​


​13​

​<​​​Button​ ​​x:Name​​​​=​​​​"btnLibrary"​​ ​​Margin​​​​=​​​​"10"​​ ​​Command​​​​=​​​​"New"​​ ​​CommandParameter​​​​=​​​​"Library"​​​​>新建Library</​​​Button​​​> ​


​14​

​</​​​StackPanel​​​> ​


​15​

​</​​​Window​​​>​


后台代码:




​view source​​​​print​​​​?​



​01​

using​ ​​System; ​


​02​

using​ ​​System.Collections.Generic; ​


​03​

using​ ​​System.Windows; ​


​04​

using​ ​​System.Windows.Data; ​


​05​

using​ ​​System.Windows.Documents; ​


​06​

using​ ​​System.Windows.Controls; ​


​07​

using​ ​​System.Windows.Input; ​


​08​

 


​09​

namespace​ ​​DeepXAML ​


​10​

​{ ​


​11​

public​ ​partial​ ​class​ ​​MainWindow : Window ​


​12​

​{ ​


​13​

 


​14​

public​ ​​MainWindow() ​


​15​

​{ ​


​16​

​InitializeComponent(); ​


​17​

​} ​


​18​

 


​19​

private​ ​void​ ​​New_CanExecute(​​​object​ ​​sender, CanExecuteRoutedEventArgs e) ​


​20​

​{ ​


​21​

​e.CanExecute = ​​​string​​​.IsNullOrEmpty(textBox.Text); ​


​22​

​} ​


​23​

 


​24​

private​ ​void​ ​​New_Executed(​​​object​ ​​sender, ExecutedRoutedEventArgs e) ​


​25​

​{ ​


​26​

if​ ​​(e.Parameter.ToString() == ​​​​"Library"​​​​) ​


​27​

​{ ​


​28​

this​​​.textBox.Text+= ​​​​"建一个Library"​​​​; ​


​29​

​} ​


​30​

if​ ​​(e.Parameter.ToString() == ​​​​"WPF"​​​​) ​


​31​

​{ ​


​32​

this​​​.textBox.Text += ​​​​"建一个WPF"​​​​; ​


​33​

​}             ​


​34​

​} ​


​35​

​}            ​


​36​

​}​


 

运行:

WPF-命令_WPF_04

点击第一个按钮

WPF-命令_xml_05

清空文本框再点击第二个按钮

WPF-命令_内置_06