基础知识:
- 命令是应用程序的任务,并跟踪任务是否能够被执行。
- 命令不包含执行应用程序任务的代码。
- 命令是比事件更高级的元素。默认的命令目标是当前获得焦点的元素。
- 良好的Win应用程序,应用程序逻辑不应位于事件处理程序中,而应在更高层的方法中编写代码。
- 将事件委托到适当的命令,使控件的启动状态和相应命令的状态保持同步。
- WPF命令模型:
图1 WPF命令模型
7. System.Windows.Input.RoutedCommand类是WPF中唯一实现了ICommand接口的类。它不包含任何应用程序逻辑,而只代表命令。
8. ICommand的定义:
// 摘要: // 定义一个命令 [TypeConverter("System.Windows.Input.CommandConverter, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")] [TypeForwardedFrom("PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")] [ValueSerializer("System.Windows.Input.CommandValueSerializer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")] public interface ICommand { // 摘要: // 当出现影响是否应执行该命令的更改时发生。 event EventHandler CanExecuteChanged; // 摘要: // 定义用于确定此命令是否可以在其当前状态下执行的方法。 // // 参数: // parameter: // 此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 null。 // // 返回结果: // 如果可以执行此命令,则为 true;否则为 false。 bool CanExecute(object parameter); // // 摘要: // 定义在调用此命令时调用的方法。 // // 参数: // parameter: // 此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 null。 void Execute(object parameter); }
9. RoutedCommand的定义:
// 摘要: // 定义一个实现 System.Windows.Input.ICommand 并通过元素树路由的命令。 [TypeConverter("System.Windows.Input.CommandConverter, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")] [ValueSerializer("System.Windows.Input.CommandValueSerializer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")] public class RoutedCommand : ICommand { // 摘要: // 初始化 System.Windows.Input.RoutedCommand 类的新实例。 public RoutedCommand(); // // 摘要: // 使用指定的名称和所有者类型初始化 System.Windows.Input.RoutedCommand 类的新实例。 // // 参数: // name: // 序列化的声明名称。 // // ownerType: // 注册命令的类型。 // // 异常: // System.ArgumentNullException: // name 为 null。 // // System.ArgumentException: // name 的长度为零。 // // System.ArgumentException: // name 的长度为零。 public RoutedCommand(string name, Type ownerType); // // 摘要: // 使用指定的名称、所有者类型和笔势集合初始化 System.Windows.Input.RoutedCommand 类的新实例。 // // 参数: // name: // 序列化的声明名称。 // // ownerType: // 正在注册命令的类型。 // // inputGestures: // 与此命令关联的默认输入笔势。 // // 异常: // System.ArgumentNullException: // name 为 null。 // // System.ArgumentException: // name 的长度为零。 - 或 - ownerType 为 null。 public RoutedCommand(string name, Type ownerType, InputGestureCollection inputGestures); // 摘要: // 获取与此命令关联的 System.Windows.Input.InputGesture 对象的集合。 // // 返回结果: // 输入笔势。 public InputGestureCollection InputGestures { get; } // // 摘要: // 获取命令的名称。 // // 返回结果: // 命令的名称。 public string Name { get; } // // 摘要: // 获取使用命令注册的类型。 // // 返回结果: // 命令所有者的类型。 public Type OwnerType { get; } // 摘要: // 当命令管理器检测到对命令源所进行的更改时发生。 这些更改通常影响是否应对当前命令目标执行命令。 public event EventHandler CanExecuteChanged; // 摘要: // 确定此 System.Windows.Input.RoutedCommand 在其当前状态是否可以执行。 // // 参数: // parameter: // 用户定义的数据类型。 // // target: // 命令目标。 // // 返回结果: // 如果可以对当前命令目标执行此命令,则为 true;否则为 false。 // // 异常: // System.InvalidOperationException: // target 不是 System.Windows.UIElement 或 System.Windows.ContentElement。 [SecurityCritical] public bool CanExecute(object parameter, IInputElement target); // // 摘要: // 对当前命令目标执行 System.Windows.Input.RoutedCommand。 // // 参数: // parameter: // 要传递到处理程序的用户定义的参数。 // // target: // 要在其中查找命令处理程序的元素。 // // 异常: // System.InvalidOperationException: // target 不是 System.Windows.UIElement 或 System.Windows.ContentElement。 [SecurityCritical] public void Execute(object parameter, IInputElement target); }
10. 命令源是命令的发出者,须是实现ICommandSource接口的类。定义如下:
// 摘要: // 定义了解如何调用命令的对象。 public interface ICommandSource { // 摘要: // 获取将在调用命令源时执行的命令。 // // 返回结果: // 将在调用命令源时执行的命令。 ICommand Command { get; } // // 摘要: // 表示可在执行命令时传递给该命令的用户定义的数据值。 // // 返回结果: // 命令特定数据。 object CommandParameter { get; } // // 摘要: // 将在其上执行命令的对象。 // // 返回结果: // 将在其上执行命令的对象。 IInputElement CommandTarget { get; } }
11. 命令目标即命令作用的目标,须是实现了IInputElement接口的类。定义如下:
// 摘要: // 为 Windows Presentation Foundation (WPF) 元素进行的基本输入处理建立公共事件,以及事件相关属性和方法。 public interface IInputElement { // 摘要: // 获取或设置一个值,该值指示是否可将焦点设置到此元素。 // // 返回结果: // 如果可将焦点设置到此元素,则为 true;否则为 false。 bool Focusable { get; set; } // // 摘要: // 获取一个值,该值指示是否在 用户界面 (UI) 中启用了此元素。 // // 返回结果: // 如果启用了该元素,则为 true;否则为 false。 bool IsEnabled { get; } // // 摘要: // 获取一个值,该值指示此元素是否具有键盘焦点。 // // 返回结果: // 如果此元素具有键盘焦点,则为 true;否则为 false。 bool IsKeyboardFocused { get; } // // 摘要: // 获取一个值,该值指示键盘焦点是否在元素边界内的任何地方,包括键盘焦点是否在任何可见子元素的边界内。 // // 返回结果: // 如果键盘焦点在元素或其子元素上,则为 true;否则为 false。 bool IsKeyboardFocusWithin { get; } // // 摘要: // 获取一个值,该值指示是否将鼠标捕获到此元素。 // // 返回结果: // 如果元素具有鼠标捕获,则为 true;否则为 false。 bool IsMouseCaptured { get; } // // 摘要: // 获取一个值,该值指示在最严格的命中测试意义上鼠标指针是否位于此元素上。 // // 返回结果: // 如果鼠标指针位于此元素上,则为 true;否则为 false。 bool IsMouseDirectlyOver { get; } // // 摘要: // 获取一个值,该值指示鼠标指针是否位于此元素(包括其边界内的可见子元素)上。 // // 返回结果: // 如果鼠标指针位于此元素或其子元素上,则为 true;否则为 false。 bool IsMouseOver { get; } // // 摘要: // 获取一个值,该值指示是否将触笔捕获到此元素。 // // 返回结果: // 如果元素具有触笔捕获,则为 true;否则为 false。 bool IsStylusCaptured { get; } // // 摘要: // 获取一个值,该值指示在最严格的命中测试意义上触笔是否位于此元素上。 // // 返回结果: // 如果触笔位于此元素上,则为 true;否则为 false。 bool IsStylusDirectlyOver { get; } // // 摘要: // 获取一个值,该值指示触笔是否位于此元素(或其边界内的可见子元素)上。 // // 返回结果: // 如果触笔光标位于此元素或其子元素上,则为 true;否则为 false。 bool IsStylusOver { get; } // 摘要: // 在键盘焦点位于此元素上时发生。 event KeyboardFocusChangedEventHandler GotKeyboardFocus; // // 摘要: // 在元素捕获到鼠标时发生。 event MouseEventHandler GotMouseCapture; // // 摘要: // 在元素捕获到触笔时发生。 event StylusEventHandler GotStylusCapture; // // 摘要: // 在键盘焦点位于此元素上并按下一个键时发生。 event KeyEventHandler KeyDown; // // 摘要: // 在键盘焦点位于此元素上并释放一个键时发生。 event KeyEventHandler KeyUp; // // 摘要: // 在键盘焦点不再位于此元素上时发生。 event KeyboardFocusChangedEventHandler LostKeyboardFocus; // // 摘要: // 在此元素失去鼠标捕获时发生。 event MouseEventHandler LostMouseCapture; // // 摘要: // 在此元素失去触笔捕获时发生。 event StylusEventHandler LostStylusCapture; // // 摘要: // 在鼠标指针进入此元素的边界时发生。 event MouseEventHandler MouseEnter; // // 摘要: // 在鼠标指针离开此元素的边界时发生。 event MouseEventHandler MouseLeave; // // 摘要: // 当鼠标指针位于元素上并按下鼠标左键时发生。 event MouseButtonEventHandler MouseLeftButtonDown; // // 摘要: // 当鼠标指针位于元素上并释放鼠标左键时发生。 event MouseButtonEventHandler MouseLeftButtonUp; // // 摘要: // 当鼠标指针在元素上移动时发生。 event MouseEventHandler MouseMove; // // 摘要: // 当鼠标指针位于元素上并按下鼠标右键时发生。 event MouseButtonEventHandler MouseRightButtonDown; // // 摘要: // 当鼠标指针位于元素上并释放鼠标右键时发生。 event MouseButtonEventHandler MouseRightButtonUp; // // 摘要: // 当鼠标指针位于此元素上并且鼠标滚轮移动时发生。 event MouseWheelEventHandler MouseWheel; // // 摘要: // 在键盘焦点位于此元素上时发生。 event KeyboardFocusChangedEventHandler PreviewGotKeyboardFocus; // // 摘要: // 在键盘焦点位于此元素上并按下一个键时发生。 event KeyEventHandler PreviewKeyDown; // // 摘要: // 在键盘焦点位于此元素上并释放一个键时发生。 event KeyEventHandler PreviewKeyUp; // // 摘要: // 在键盘焦点不再位于此元素上时发生。 event KeyboardFocusChangedEventHandler PreviewLostKeyboardFocus; // // 摘要: // 当鼠标指针位于元素上并按下鼠标左键时发生。 event MouseButtonEventHandler PreviewMouseLeftButtonDown; // // 摘要: // 当鼠标指针位于元素上并释放鼠标左键时发生。 event MouseButtonEventHandler PreviewMouseLeftButtonUp; // // 摘要: // 当鼠标指针在元素上移动时发生。 event MouseEventHandler PreviewMouseMove; // // 摘要: // 当鼠标指针位于元素上并按下鼠标右键时发生。 event MouseButtonEventHandler PreviewMouseRightButtonDown; // // 摘要: // 当鼠标指针位于元素上并释放鼠标右键时发生。 event MouseButtonEventHandler PreviewMouseRightButtonUp; // // 摘要: // 当鼠标指针位于此元素上并且鼠标滚轮移动时发生。 event MouseWheelEventHandler PreviewMouseWheel; // // 摘要: // 当触笔位于此元素上并按下触笔按钮时发生。 event StylusButtonEventHandler PreviewStylusButtonDown; // // 摘要: // 当触笔位于此元素上并释放触笔按钮时发生。 event StylusButtonEventHandler PreviewStylusButtonUp; // // 摘要: // 当触笔悬停于此元素上并接触数字化仪时发生。 event StylusDownEventHandler PreviewStylusDown; // // 摘要: // 当触笔从元素上移开但并未接触数字化仪时发生。 event StylusEventHandler PreviewStylusInAirMove; // // 摘要: // 当触笔离要检测的数字化仪足够近时发生。 event StylusEventHandler PreviewStylusInRange; // // 摘要: // 当触笔在元素上移动时发生。 event StylusEventHandler PreviewStylusMove; // // 摘要: // 当触笔离要检测的数字化仪足够远时发生。 event StylusEventHandler PreviewStylusOutOfRange; // // 摘要: // 当检测到若干触笔笔势之一时发生,例如 System.Windows.Input.SystemGesture.Tap 或 System.Windows.Input.SystemGesture.Drag。 event StylusSystemGestureEventHandler PreviewStylusSystemGesture; // // 摘要: // 当触笔悬停于此元素上并从数字化仪上移开时发生。 event StylusEventHandler PreviewStylusUp; // // 摘要: // 在此元素以与设备无关的方式获取文本时发生。 event TextCompositionEventHandler PreviewTextInput; // // 摘要: // 当触笔位于此元素上并按下触笔按钮时发生。 event StylusButtonEventHandler StylusButtonDown; // // 摘要: // 当触笔位于此元素上并释放触笔按钮时发生。 event StylusButtonEventHandler StylusButtonUp; // // 摘要: // 当触笔悬停于此元素上并接触数字化仪时发生。 event StylusDownEventHandler StylusDown; // // 摘要: // 在触笔光标进入元素边界时发生。 event StylusEventHandler StylusEnter; // // 摘要: // 当触笔从元素上移开但并未接触数字化仪时发生。 event StylusEventHandler StylusInAirMove; // // 摘要: // 当触笔离要检测的数字化仪足够近时发生。 event StylusEventHandler StylusInRange; // // 摘要: // 在触笔光标离开元素边界时发生。 event StylusEventHandler StylusLeave; // // 摘要: // 在触笔光标移到元素上时发生。 event StylusEventHandler StylusMove; // // 摘要: // 当触笔离要检测的数字化仪足够远时发生。 event StylusEventHandler StylusOutOfRange; // // 摘要: // 当检测到若干触笔笔势之一时发生,例如 System.Windows.Input.SystemGesture.Tap 或 System.Windows.Input.SystemGesture.Drag。 event StylusSystemGestureEventHandler StylusSystemGesture; // // 摘要: // 当触笔悬停于此元素上并从数字化仪上移开时发生。 event StylusEventHandler StylusUp; // // 摘要: // 在此元素以与设备无关的方式获取文本时发生。 event TextCompositionEventHandler TextInput; // 摘要: // 将用于特定路由事件的路由事件处理程序添加到元素。 // // 参数: // routedEvent: // 正在处理的路由事件的标识符。 // // handler: // 对处理程序实现的引用。 void AddHandler(RoutedEvent routedEvent, Delegate handler); // // 摘要: // 尝试将鼠标强制捕获到此元素。 // // 返回结果: // 如果成功捕获了鼠标,则为 true;否则为 false。 bool CaptureMouse(); // // 摘要: // 尝试将触笔强制捕获到此元素。 // // 返回结果: // 如果成功捕获了触笔,则为 true;否则为 false。 bool CaptureStylus(); // // 摘要: // 尝试使键盘焦点位于此元素上。 // // 返回结果: // 如果键盘焦点移动到此元素,或者已经在此元素上,则为 true;否则为 false。 bool Focus(); // // 摘要: // 引发路由事件,该事件由所提供的 System.Windows.RoutedEventArgs 内的 System.Windows.RoutedEventArgs.RoutedEvent // 属性指定。 // // 参数: // e: // 包含要引发事件标识符的 System.Windows.RoutedEventArgs 类的实例。 void RaiseEvent(RoutedEventArgs e); // // 摘要: // 如果此元素具有鼠标捕获,则释放该捕获。 void ReleaseMouseCapture(); // // 摘要: // 如果此元素具有触笔捕获,则释放该捕获。 void ReleaseStylusCapture(); // // 摘要: // 从此元素中移除指定路由事件处理程序的所有实例。 // // 参数: // routedEvent: // 为其附加了处理程序的路由事件的标识符。 // // handler: // 要从此元素的事件处理程序集合移除的特定处理程序实现。 void RemoveHandler(RoutedEvent routedEvent, Delegate handler); }
12. 命令绑定,负责将某些外围逻辑与命令关联起来,须在命令目标的外围控件上,否则捕捉不到CanExecute和Executed等路由事件。CommandBinding定义如下:
// 摘要: // 将 System.Windows.Input.RoutedCommand 绑定到实现该命令的事件处理程序。 public class CommandBinding { // 摘要: // 初始化 System.Windows.Input.CommandBinding 类的新实例。 public CommandBinding(); // // 摘要: // 使用指定的 System.Windows.Input.ICommand 初始化 System.Windows.Input.CommandBinding // 类的新实例。 // // 参数: // command: // 新的 System.Windows.Input.RoutedCommand 所基于的命令。 public CommandBinding(ICommand command); // // 摘要: // 使用指定的 System.Windows.Input.ICommand 和指定的 System.Windows.Input.CommandBinding.Executed // 事件处理程序初始化 System.Windows.Input.CommandBinding 类的新实例。 // // 参数: // command: // 新的 System.Windows.Input.RoutedCommand 所基于的命令。 // // executed: // 新 System.Windows.Input.RoutedCommand 上的 System.Windows.Input.CommandBinding.Executed // 事件的处理程序。 public CommandBinding(ICommand command, ExecutedRoutedEventHandler executed); // // 摘要: // 使用指定的 System.Windows.Input.ICommand 和指定的 System.Windows.Input.CommandBinding.Executed // 及 System.Windows.Input.CommandBinding.CanExecute 事件处理程序初始化 System.Windows.Input.CommandBinding // 类的新实例。 // // 参数: // command: // 新的 System.Windows.Input.RoutedCommand 所基于的命令。 // // executed: // 新 System.Windows.Input.RoutedCommand 上的 System.Windows.Input.CommandBinding.Executed // 事件的处理程序。 // // canExecute: // 新 System.Windows.Input.RoutedCommand 上的 System.Windows.Input.CommandBinding.CanExecute // 事件的处理程序。 public CommandBinding(ICommand command, ExecutedRoutedEventHandler executed, CanExecuteRoutedEventHandler canExecute); // 摘要: // 获取或设置与此 System.Windows.Input.CommandBinding 关联的 System.Windows.Input.ICommand。 // // 返回结果: // 与此绑定关联的命令。 [Localizability(LocalizationCategory.NeverLocalize)] public ICommand Command { get; set; } // 摘要: // 当与该 System.Windows.Input.CommandBinding 关联的命令启动检查以确定是否可以在命令目标上执行此命令时发生。 public event CanExecuteRoutedEventHandler CanExecute; // // 摘要: // 当执行与该 System.Windows.Input.CommandBinding 关联的命令时发生。 public event ExecutedRoutedEventHandler Executed; // // 摘要: // 当与该 System.Windows.Input.CommandBinding 关联的命令启动检查以确定是否可以在当前命令目标上执行此命令时发生。 public event CanExecuteRoutedEventHandler PreviewCanExecute; // // 摘要: // 当执行与该 System.Windows.Input.CommandBinding 关联的命令时发生。 public event ExecutedRoutedEventHandler PreviewExecuted; }
13. 关于命令的代码示例见:http://www.cnblogs.com/lzhp/archive/2012/09/25/2695252.html