【WPF學習】第三十一章 WPF命令模型
WPF命令模型由許多可變的部分組成。總之,它們都具有如下4個重要元素:
- 命令:命令表示應用程式任務,並且跟蹤任務是否能夠被執行。然而,命令實際上不包含執行應用程式任務的程式碼。
- 命令繫結:每個命令繫結針對使用者介面的具體區域,將命令連線到相關的應用程式邏輯。這種分解的設計是非常重要的,因為單個命令可用於應用程式中的多個地方,並且在每個地方具有不同的意義。為處理這一問題,需要將同一命令與不同的命令繫結。
- 命令源:命令源觸發命令。例如,MenuItem和Button都是命令源。單擊它們都會執行繫結命令。
- 命令目標:命令目標是在其中執行命令的元素。例如,Paste命令可在TextBox控制元件中插入文字,而OpenFile命令可在DocumentViewer中開啟文件。根據命令的本質,目標可能很重要,也可能不重要。
一、ICommand介面
WPF命令模型的核心是System.Windows.Input.ICommand介面,該介面定義了命令的工作原理。該介面包含兩個方法和一個事件:
public interface ICommand { void Execute(object parameter); bool CanExecute(object parameter); event EventHandler CanExecuteChanged; }
在一個簡單實現中,Execute()方法將包含應用程式任務邏輯(例如,列印文件)。然而,正如下一節中將看到,WPF的實現更復雜。它使用Execute()方法引發一個更復雜的過程,該過程最終觸發在應用程式其他地方處理的事件。通過這種方式可以使用預先準備好的命令類,並插入自己的邏輯。還可以靈活地再幾個不同地方使用同一個命令(如Print命令)。
CanExecute()方法返回命令的狀態——如果命令可用,就返回true;如果不可用,就返回false。Execute()和CanExecute()方法都接受一個附加的引數物件,可使用該物件傳遞所需的任何附加資訊。
最初,當命令狀態改變時引發CanExecuteChanged事件。對於使用命令的任何事件,這是指示訊號,表示它們應當呼叫CanExecute()方法檢查命令的狀態。通過使用該事件,當命令可用時,命令源(如Button或MenuItem)可自動啟用自身;當命令不可用時,禁用自身。
二、RoutedCommand類
當建立自己的命令時,不會直接實現ICommand介面;而是使用System.Windows.Input.RoutedCommand類,該類自動實現了ICommand介面。RoutedCommand類是WPF中唯一實現了ICommand介面的類。換句話說,所有WPF命令都是RoutedCommand類及其派生類的例項。
在WPF命令模型背後的一個重要概念是,RoutedCommand類不包含任何應用程式邏輯,而只代表命令,這意味著各個RoutedCommand物件具有相同的功能。
RoutedCommand類為事件冒泡和隧道添加了一些額外的基礎結構。鑑於ICommand介面封裝了命令的思想——可被觸發的動作並可被啟用或禁用——RoutedCommand類對命令進行了修改,使命令可在WPF元素層次結構中冒泡,以便獲得正確的事件處理程式。
為支援路由事件,RoutedCommand類私有地實現了ICommand介面,並添加了ICommand介面方法的一些不同版本。最明顯的變化是,Execute()和CanExecute()方法使用了一個額外引數。下面的新的簽名:
public void Execute(object parameter,IInputElement target) { //... } public void CanExecute(object parameter,IInputElement target) { //... }
引數target是開始處理事件的元素。事件從target元素開始,然後冒泡至高層的容器,直到應用程式為了執行合適的任務而處理了事件(為了處理Executed事件,元素還需要藉助於另一個類——CommandBinding類的幫助)。
除上面的修改外,RoutedCommand類還引入了三個屬性:命令名稱(Name屬性)、包含命令的類(OwnerType)以及任何可用於觸發命令的按鍵或滑鼠操作(位於InputGestures集合中)。
三、RoutedUICommand類
在程式中處理的大部分命令不是RoutedCommand物件,而是RoutedUICommand類的例項,RoutedUICommand類繼承自RoutedCommand類(實際上,WPF提供的所有預先構建好的命令都是RoutedUICommand物件)。
RoutedUICommand類用於具有文字的命令,這些文字顯示在使用者介面中的某些地方(例如選單項文字、工具欄按鈕的工具欄提示)。RoutedUICommand類只添加了Text屬性,該屬性是為命令顯示的文字。
為命令定義命令文字(而不是直接在控制元件上定義文字)的優點是可在某個位置執行本地化。但如果命令文字永遠不會在使用者介面的任何地方顯示,那麼RoutedUICommand類和RoutedCommand類是等效的。
四、命令庫
WPF設計者認識到,每個應用程式可能都有大量命令,並且對於許多不同的應用程式,很多命令時通用的,例如,所有基於文件的應用程式都有他們自己版本的New、Open以及Save命令。為減少建立這些命令所需的工作,WPF提供了基本命令庫,基本命令庫中儲存的命令超過100條。這些命令通過以下5個專門的靜態類的屬性提供:
- ApplicationCommands:該類提供了通用命令,包括剪貼簿命令(如Copy、Cut和Paste)以及文件命令(如New、Open、Save、SaveAs和Print等)。
- NavigationCommands:該類提供了用於導航的命令,包括為基於頁面的應用程式設計的一些命令(如BrowseBack、BrowSeForward和NextPage),以及其他適合於基於文件的應用程式的命令(如IncreaseZoom和Refresh).
- EditingCommands:該類提供了許多重要的文件編輯命令,包括用於移動的命令(MoveToLineEnd、MoveLeftByWord和MoveUpByPage等),選擇內容的命令(SelectToLineEnd、SelectLeftByWord),以及改變格式的命令(ToggleBold和ToggleUnderLine)。
- ComponentCommands:該類提供了由使用者介面元件使用的命令,包括用於移動和選擇內容的命令,這些命令和EditingCommands類中的一些命令類似(甚至完全相同)。
- MediaCommands:該類提供了一組用於處理多媒體的命令(如Play、Pause、NextTrack以及IncreaseVolume).
ApplicationCommands類提供了一組基本命令,在所有類別的應用程式中都經常會用到這些命令,所以在此簡單介紹一下。下面列出了所有這些命令。
New | Copy | SelectAll |
Open | Cut | Stop |
Save | Paste | ContextMenu |
SaveAs |
Delete | CorrectionList |
Close | Undo | Properties |
Redo | Help | |
PrintPreview | Find | |
CancelPrint | Replace |
例如,ApplicationCommands.Open是提供RoutedUICommand物件的靜態屬性,該物件表示應用程式中的Open命令。因為ApplicationCommands.Open是靜態屬性,所以在整個應用程式中只有一個Open命令例項。然而,根據命令源的不同(換句話說,是在使用者介面的什麼地方觸發的該命令),可採用不同的處理方式。
每個命令的RoutedUICommand.Text屬性和名稱是相互匹配的,指示在單詞之間添加了空格。例如,ApplicationCommands.SelectedAll命令的文字時SelecteAll(Name屬性使用相同的沒有空格的文字)。因為Open命令時ApplicationCommands類的靜態屬性,所以RoutedUICommand.OwnerType屬性返回ApplicationCommands類的型別物件。
這些單獨的命令物件僅時一些標誌起,不具有實際功能。然而,許多命令物件都有一個額外的特徵:預設輸入繫結。例如,ApplicationCommands.Open命令被對映到Ctrl+O快捷鍵。只要將命令繫結到命令源,併為視窗新增命令源,這個快捷鍵就會被啟用,即使沒有在使用者介面的任何地方顯示該命令也同樣如