WPF 之命令(七)
阿新 • • 發佈:2021-02-08
# 一、前言
事件的作用是釋出和傳播一些訊息,訊息送達接收者,事件的使命也就完成了,至於訊息響應者如何處理髮送來的訊息並不做規定,每個接收者可以使用自己的行為來響應事件。即事件不具有約束力。
命令就有約束力,不僅可以約束程式碼,還可以約束步驟邏輯。
# 二、WPF 的 命令系統
WPF 中,命令系統由以下元素構成:
1. 命令(Command):實現 ICommand 介面。表示一個程式任務,並可跟蹤該任務是否完成。
2. 命令源(Commannd Source):命令的傳送者。需實現 ICommandSource 介面。
3. 命令目標(Command Target):命令的接收者。需實現 IInputElment 介面的類。
4. 命令關聯(Command Binding):負責把外圍邏輯和命令關聯起來。
![image-20210208165152323](https://i.loli.net/2021/02/08/nEBSZHTjvsK4wM1.png)
WPF中提供了一組已定義命令,命令包括以下類:[ApplicationCommands](http://msdn.microsoft.com/zh-cn/library/system.windows.input.applicationcommands(v=vs.110).aspx)、[NavigationCommands](http://msdn.microsoft.com/zh-cn/library/system.windows.input.navigationcommands(v=vs.110).aspx)、[MediaCommands](http://msdn.microsoft.com/zh-cn/library/system.windows.input.mediacommands(v=vs.110).aspx)、[EditingCommands](http://msdn.microsoft.com/zh-cn/library/system.windows.documents.editingcommands(v=vs.110).aspx) 以及[ComponentCommands](http://msdn.microsoft.com/zh-cn/library/system.windows.input.componentcommands(v=vs.110).aspx)。 這些類提供諸如 [Cut](http://msdn.microsoft.com/zh-cn/library/system.windows.input.applicationcommands.cut(v=vs.110).aspx)、[BrowseBack](http://msdn.microsoft.com/zh-cn/library/system.windows.input.navigationcommands.browseback(v=vs.110).aspx)、[BrowseForward](http://msdn.microsoft.com/zh-cn/library/system.windows.input.navigationcommands.browseforward(v=vs.110).aspx)、[Play](http://msdn.microsoft.com/zh-cn/library/system.windows.input.mediacommands.play(v=vs.110).aspx)、[Stop](http://msdn.microsoft.com/zh-cn/library/system.windows.input.mediacommands.stop(v=vs.110).aspx) 和 [Pause](http://msdn.microsoft.com/zh-cn/library/system.windows.input.mediacommands.pause(v=vs.110).aspx) 等命令。下面我們使用 ApplicationCommands 進行以下測試:
```c#
// 命令執行具體操作
private void CommandBinding_OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show($"New 命令被觸發了,命令源是:{e.Source}");
}
```
```html
```
點選按鈕後,輸出結果為:
```
New 命令被觸發了,命令源是:System.Windows.Controls.Button: New
```
# 三、自定義命令
例如,我們需要增加一個數據的查庫與上傳資料操作,那麼需要實現 Query 和 Insert 命令,為了能夠直接供 UI 使用,我們宣告 RoutedUICommand 命令,具體如下:
```c#
public class DatabaseCommands
{
private static RoutedUICommand _query;
private static RoutedUICommand _insert;
static DatabaseCommands()
{
InputGestureCollection inputs = new InputGestureCollection();
inputs.Add(new KeyGesture(Key.Q ,ModifierKeys.Control, "Ctrl+R"));
_query = new RoutedUICommand(
"Query", "Query", typeof(DatabaseCommands), inputs);
inputs.Add(new KeyGesture(Key.D, ModifierKeys.Control, "Ctrl+D"));
_insert = new RoutedUICommand(
"Add", "Add", typeof(DatabaseCommands), inputs);
}
public static RoutedUICommand Query
{
get { return _query; }
}
public static RoutedUICommand Insert
{
get { return _insert; }
}
}
```
命令實現與繫結到 UI 上的操作如下:
```c#
// 命令執行具體操作
private void DatabaseCommandsQuery_OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show($"Query 命令被觸發了,命令源是:{e.Source}");
}
private void DatabaseCommandsAdd_OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show($"Add 命令被觸發了,命令源是:{e.Source}");
}
```
```
```
當我們點選 Query 和 Insert 操作時,分別執行對應的操作。上述例子中,Command 的執行程式碼是在 XAML 中宣告的,那我們把命令的執行程式碼進行程式碼後置,且為了滿足不同的條件,我們宣告一個 RelayCommand 基類進行封裝,具體如下:
```c#
///
/// The base implementation of a command.
///
abstract class CommandBase : ICommand
{
///
/// Occurs when changes occur that affect whether or not the command should execute.
///
public event EventHandler CanExecuteChanged
{
add { System.Windows.Input.CommandManager.RequerySuggested += value; }
remove { System.Windows.Input.CommandManager.RequerySuggested -= value; }
}
///
/// Raises the event.
///
public void OnCanExecuteChanged()
{
System.Windows.Input.CommandManager.InvalidateRequerySuggested();
}
///
/// Defines the method that determines whether the command can execute in its current state.
///
/// Data used by the command. If the command does not require data to be passed, this object can be set to null.
///
/// true if this command can be executed; otherwise, false.
///
public virtual bool CanExecute(object parameter)
{
return true;
}
///
/// Defines the method to be called when the command is invoked.
///
/// Data used by the command. If the command does not require data to be passed, this object can be set to null.
public void Execute(object parameter)
{
if (!CanExecute(parameter))
{
return;
}
OnExecute(parameter);
}
///
/// Executes the command.
///
/// The parameter.
protected abstract void OnExecute(object parameter);
}
///
/// The command that relays its functionality by invoking delegates.
///
class RelayCommand : CommandBase
{
private readonly Action