WPF中的命令與命令綁定(二)
WPF中的命令與命令綁定(二)
周銀輝
在WPF中,命令(Commanding)被分割成了四個部分,分別是ICommand,ICommandSource,CommandTarget和CommandBinding。下面我們來分別探討這四個部分。
1,ICommand
Command也就是我們的“命令”本身,比如“復制”“粘貼”。在WPF中,所有的命令都必須實現ICommand接口,它為所有的命令提供一個抽象,這個抽象對於我們實現Undo、Redo操作非常重要,如果你學習一下設計模式中的“命令”模式,你會更加深刻的理解。
ICommand接口中擁有Execute()方法,該方法用於命令的執行(不過,註意:命令的執行邏輯——比如將剪切板中的文本去出來放到文本框的合適位置——並沒有被編寫到該方法中,稍後我們會講到這其中的奧妙),另外的一個方法是CanExecute()用於指示當前命令在目標元素上是否可用,當這種可用性發生改變時其便會引發該接口的尾頁一個事件CanExecuteChanged。
在目前的WPF類庫中,你能看到唯一一個實現了ICommand接口的類型RoutedCommand(其實還有一個名為SecureUICommand的類也實現了該接口,不過該類未被公開),“Routed”是一個不太容易被翻譯的修飾詞(有人將它翻譯為“路由”),但這意味著該類型的命令可以向WPF中的RoutedEvent一樣在元素樹中上下傳遞。
RoutedCommand的子類RoutedUICommand是我們經常使用的類型,它與RoutedCommand的不同之處僅僅在與它多了一個Text屬性來描述該命令,不過大多數WPF內置命令的Text屬性有一個很不錯的特點:其支持自動本地化。這至少會為我們的軟件的本地化減少工作量。
在本系列隨筆的後續部分將介紹如何自定義一個命令。
2,ICommandSource與CommandTarget
命令源,用來觸發我們的命令,比如用一個菜單項來觸發“復制”命令,那麽該菜單項就是命令源。要使一個元素成為命令源,其必須實現ICommandSource接口。命令源決定了它所要觸發的命令、該命令所作用的對象以及命令參數(如果需要的話),這分別對應於它的三個屬性:Command、CommandTarget以及CommandParameter。其中需要註意的是CommandTarget,因為在WPF中如果你不為命令源指定其命令對象,那麽其將會把界面上獲得鍵盤焦點的元素作為默認的命令對象,這為我們提供了方便,比如界面上有兩個文本框,我們不必擔心主菜單項上的“粘貼”操作是針對哪個文本框的,誰獲得焦點便針對誰,這符合大家的習慣。但引入的問題是,如果命令目標不具備獲取鍵盤焦點的能力(比如Label)或命令源會搶占焦點(比如用Button來代替菜單項,點擊按鈕時焦點由文本框轉移到了按鈕上),你的命令將會無效,這時你就必須為命令源指定命令目標。
在本系列隨筆的後續部分將介紹如何讓你的自定義控件成為命令源和命令目標。
3,CommandBinding
前面已經提到我們並沒有將命令的執行邏輯編寫到其Excute()方法中,這是有道理的,比如"粘貼"命令(ApplicationCommands.Paste),粘貼一段文本到文本框和粘貼一個圖片到繪圖板的執行邏輯肯定是不一樣的,負責開發該“粘貼”命令的開發人員不可能知道所有的粘貼操作的具體邏輯,使用“粘貼”命令的客戶也不應該為該執行邏輯負責,編寫該執行邏輯的任務應該被分發給那些支持“粘貼”操作的控件的開發人員以及那些希望為自己的控件添加“粘貼”操作的客戶。也就是說我們需要將“行為的請求者(命令)”和“行為的執行者(命令的執行邏輯)”分開而實現一種松耦合,而CommandBinding(命令綁定)便是命令和命令執行邏輯的橋接器。
我們使用CommandBinding將命令與其合適的執行邏輯綁定在一起:
ApplicationCommands.Close, CloseCommandHandler, CanExecuteHandler);
CommandBinding構造方法的最後兩個參數分別是ExecutedRoutedEventHandler 與 CanExecuteRoutedEventHandler 類型的委托,用於指示如何執行命令和如何判斷命令能否被執行。
與CommandBinding一樣扮演著中間角色的還有CommandManager類,它為命令綁定(以及輸入綁定)提供了很多實用方法。
在本系列隨筆的後續部分將介紹WPF的命令系統與“命令模式”(設計模式之一)之間的關系。
WPF中的命令與命令綁定(二)