1、概述

1.1 WPF C# 命令的本质

命令是 WPF 中的输入机制,它提供的输入处理比设备输入具有更高的语义级别。 例如,在许多应用程序中都能找到的“复制”、“剪切”和“粘贴”操作就是命令。

WPF 中的命令是通过实现 ICommand 接口创建的。 ICommand 的 WPF 实现是 RoutedCommand 类,这是WPF C# 命令的本质。

1.2 WPF C# 命令的机制

1.2.1 编程范围

ICommand 公开两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged)。

Execute 执行与命令关联的操作。

CanExecute 确定是否可以在当前命令目标上执行命令。

如果集中管理命令操作的命令管理器检测到命令源中发生了更改,此更改可能使得已引发但尚未由命令绑定执行的命令无效,则将引发 CanExecuteChanged

1.2.2 输入源

WPF 中的主要输入源是鼠标、键盘、墨迹和路由命令。 更加面向设备的输入使用路由事件( RoutedEvent )来通知应用程序页中的对象已发生了输入事件。无论何种输入源, RoutedCommand 没有不同。

1.2.3 应用程序逻辑

RoutedCommand 的 Execute 和 CanExecute 方法不包含命令的应用程序逻辑,而是引发这样的路由事件:沿元素树以隧道和冒泡形式传递,直到遇到具有 CommandBinding 的对象。CommandBinding 包含这些事件的处理程序,执行此命令的就是这些处理程序。( 有关 WPF 中的事件路由的更多信息,请参见路由事件概述。)

1.2.4 命令引发路由事件

RoutedCommand 上的 Execute 方法在命令目标上引发 PreviewExecuted 和 Executed 事件。

RoutedCommand 上的 CanExecute 方法在命令目标上引发 CanExecute 和PreviewCanExecute 事件。

这些事件沿元素树以隧道和冒泡形式传递,直到遇到具有该特定命令的 CommandBinding 的对象。

1.3、WPF C# 命令分类

WPF 通过命令类库提供一组预定义命令。如果命令库类中的命令不满足您的需要,则您可以创建自己的命令。

1.3.1 内置命令库

WPF 提供一组预定义命令库。 命令库包含以下类:ApplicationCommandsNavigationCommandsMediaCommandsEditingCommands 以及 ComponentCommands

这些类提供了一组常用的路由命令.诸如 CutBrowseBackBrowseForwardPlayStop 和 Pause 等命令。

这些命令仅包含 RoutedCommand 对象,而不包含命令的实现逻辑。 实现逻辑由在其上执行命令的对象负责。

命令库中的许多命令都包括一组默认输入绑定。 例如,如果您指定应用程序处理复制命令,则会自动获得键盘绑定“Ctrl+C”。您还会获得其他输入设备(如 Tablet PC 钢笔笔势和语音信息)的绑定。

当您使用 XAML 引用不同的命令库中的命令时,通常可以忽略公开静态命令属性的库类的类名。 通常,命令名称作为字符串是明确的,并且存在用于提供命令的逻辑分组的所属类型,但是这些类型对于消除歧义并不是必需的。 例如,您可以指定 Command="Cut",而不必指定更详细的 Command="ApplicationCommands.Cut"。 这是一种内置于命令的 WPF XAML 处理器中的便利机制(更准确地说,它是 WPF XAML 处理器在加载时引用的 ICommand 的类型转换器行为)。

1.3.2 创建自定义命令

如果命令库类中的命令不满足您的需要,则您可以创建自己的命令。

有两种方法可创建自定义命令。 第一种是从头开始,并实现 ICommand 接口。 另一种方法,也是更常用的方法,是创建RoutedCommand 或 RoutedUICommand

有关创建自定义 RoutedCommand 的示例,请参见 Create a Custom RoutedCommand Sample(创建自定义 RoutedCommand 示例)。

1.4、WPF C# 命令的用途

命令有若干用途。

1.4.1 将语义以及调用命令的对象与执行命令的逻辑分离

第一个用途是将语义以及调用命令的对象与执行命令的逻辑分离开来。 这使得多个完全不同的源可以调用相同的命令逻辑,并使得可以针对不同的目标对命令逻辑进行自定义。 例如,在许多应用程序中都能找到的编辑操作“复制”、“剪切”和“粘贴”都可使用不同的用户操作进行调用(如果这些操作是使用命令实现的)。 应用程序可能允许用户通过单击按钮、选择菜单项或使用组合键(例如 Ctrl+X)剪切所选的对象或文本。 通过使用命令,您可以将各种类型的用户操作绑定到同一逻辑。

1.4.2 操作是否可用

命令的另一个用途是指示操作是否可用。 仍然以剪切对象或文本作为示例,该操作只有在选择了某些内容时才有意义。 如果用户尝试在没有选择任何内容的情况下剪切对象或文本,则不会发生任何操作。 为了向用户指明这一点,许多应用程序都会禁用按钮和菜单项,以使用户了解是否能够执行某项操作。 命令可通过实现 CanExecute 方法来指出操作是否可以执行。 按钮可以订阅CanExecuteChanged 事件,并且,如果 CanExecute 返回 false,则可以禁用按钮,或者,如果 CanExecute 返回 true,则可以启用按钮。

1.4.3 根据目标的类型采取相应的操作

命令的语义在应用程序和类之间可能是一致的,但是操作的逻辑是所作用于的特定对象所特有的。 Ctrl+X 组合键在文本类、图像类以及 Web 浏览器中调用“剪切”命令,但用于执行“剪切”操作的实际逻辑是由执行剪切的应用程序定义的。 RoutedCommand 使客户端能够实现逻辑。 文本对象可以将所选文本剪切到剪贴板中,而图像对象则可以剪切所选图像。 当应用程序处理Executed 事件时,它将能访问命令的目标,并根据目标的类型采取相应的操作。

2、使用WPF 命令

2.1 WPF 命令中的四个主要概念

WPF 中的路由命令模型可以分为四个主要概念:命令、命令源、命令目标以及命令绑定:

  • 命令:是要执行的操作。

  • 命令源:是调用命令的对象。

  • 命令目标:是在其上执行命令的对象。

  • 命令绑定:是将命令逻辑映射到命令的对象。

参见下面的示例。其中,Paste 命令是命令,MenuItem 是命令源,TextBox 是命令目标,命令绑定由 TextBox 控件提供。

值得注意的是,CommandBinding 并不总是由充当命令目标类的控件提供。 非常常见的情况是,CommandBinding 必须由应用程序开发人员创建,或者 CommandBinding 可能附加到命令目标的上级。

2.2 WPF 中的简单命令示例

在 WPF 中使用命令的最简单方法是从某个命令库类中使用预定义的 RoutedCommand;使用对处理此命令具有固有支持的控件;以及使用对调用命令具有固有支持的控件。

Paste 命令是ApplicationCommands 类中的预定义命令之一。 TextBox 控件具有处理 Paste 命令的内置逻辑。 MenuItem 类具有对调用命令的固有支持。下面的示例演示如何设置 MenuItem,以便单击该菜单项时,将对 TextBox 调用 Paste 命令(假定该 TextBox 具有键盘焦点)。

XAML

<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
C#

// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem(); // Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox); // Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste; // Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;

2.3 编程设计

2.3.1 命令

如前述所述,WPF 中的命令是通过实现 ICommand 接口创建的。 ICommand 公开两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged)。 Execute 执行与命令关联的操作。CanExecute 确定是否可以在当前命令目标上执行命令。 如果集中管理命令操作的命令管理器检测到命令源中发生了更改,此更改可能使得已引发但尚未由命令绑定执行的命令无效,则将引发 CanExecuteChanged

RoutedCommand 上的 Execute 方法在命令目标上引发 PreviewExecuted 和 Executed 事件。 RoutedCommand 上的 CanExecute 方法在命令目标上引发 CanExecute 和PreviewCanExecute 事件。 这些事件沿元素树以隧道和冒泡形式传递,直到遇到具有该特定命令的 CommandBinding 的对象。

2.3.2 命令源

命令源是调用命令的对象。 例如,MenuItemButton 和 KeyGesture 就是命令源。

WPF 中的命令源通常实现 ICommandSource 接口。

ICommandSource 公开三个属性:CommandCommandTarget 和 CommandParameter

实现 ICommandSource 的 WPF 类包括:ButtonBaseMenuItemHyperlink 以及 InputBinding

ButtonBase 、MenuItem 和 Hyperlink 在被单击时调用命令,InputBinding 在与之关联的 InputGesture 执行时调用命令。

2.3.2.1 举例: ContextMenu 中的 MenuItem 用作 Properties 命令的命令源

下面的示例演示如何将 ContextMenu 中的 MenuItem 用作 Properties 命令的命令源。

XAML

<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Properties" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
C#

StackPanel cmdSourcePanel = new StackPanel();
ContextMenu cmdSourceContextMenu = new ContextMenu();
MenuItem cmdSourceMenuItem = new MenuItem(); // Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu;
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem); // Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties;

通常,命令源会侦听 CanExecuteChanged 事件。 此事件通知命令源,在当前命令目标上执行命令的能力可能已更改。 命令源可以通过使用 CanExecute 方法来查询 RoutedCommand 的当前状态。 之后,如果命令无法执行,则命令源可以禁用其自身。 这种情况的一个示例是:当无法执行命令时,MenuItem 会将自己显示为灰色。

2.3.2.2 举例: InputGesture 作命令源

可以将 InputGesture 用作命令源。 WPF 中两种类型的输入笔势是 KeyGesture 和 MouseGesture。 可以将 KeyGesture 视为键盘快捷方式,如 Ctrl+C。 KeyGesture 由一个 Key 和一组ModifierKeys 组成。 MouseGesture 由一个 MouseAction 和一组可选的 ModifierKeys 组成。

为了使 InputGesture 充当命令源,必须将它与一个命令关联。 有几种方法可实现此目的。 一种方法是使用 InputBinding

下面的示例演示如何在 KeyGesture 与 RoutedCommand 之间创建一个 KeyBinding

XAML

<Window.InputBindings>
<KeyBinding Key="B"
Modifiers="Control"
Command="ApplicationCommands.Open" />
</Window.InputBindings>
C#

KeyGesture OpenKeyGesture = new KeyGesture(
Key.B,
ModifierKeys.Control); KeyBinding OpenCmdKeybinding = new KeyBinding(
ApplicationCommands.Open,
OpenKeyGesture); this.InputBindings.Add(OpenCmdKeybinding);

2.3.2.3  InputGesture 与 RoutedCommand 关联

将 InputGesture 与 RoutedCommand 关联的另一种方法是将 InputGesture 添加到 RoutedCommand 的 InputGestureCollection

下面的示例演示如何将一个 KeyGesture 添加到 RoutedCommand 的 InputGestureCollection

WPF C# 命令的运行机制

命令源

命令源是调用命令的对象。 例如,MenuItemButton 和 KeyGesture 就是命令源。

WPF 中的命令源通常实现 ICommandSource 接口。

ICommandSource 公开三个属性:CommandCommandTarget 和 CommandParameter

实现 ICommandSource 的 WPF 类包括:ButtonBaseMenuItemHyperlink 以及 InputBinding。 ButtonBase 、MenuItem 和 Hyperlink 在被单击时调用命令,InputBinding 在与之关联的 InputGesture 执行时调用命令。

WPF C# 命令的运行机制的更多相关文章

  1. 8、WPF体系架构和运行机制

    体系架构:http://msdn.microsoft.com/zh-cn/library/ms750441.aspx 运行机制:http://www.cnblogs.com/leep2007/arch ...

  2. Java学习系列(一)Java的运行机制、JDK的安装配置及常用命令详解

    俗话说:“十五的月亮十六圆”.那学习是不是也是如此呢?如果把月亮看成是我们的愿望,那十五便是我们所处的“高原期”,坚持迈过这个坎,我相信你的愿望终究会现实的.记得马云曾说:今天很残酷,明天更残酷,后天 ...

  3. (十三)Maven插件解析运行机制

    这里给大家详细说一下Maven的运行机制,让大家不仅知其然,更知其所以然. 1.插件保存在哪里? 与我们所依赖的构件一样,插件也是基于坐标保存在我们的Maven仓库当中的.在用到插件的时候会先从本地仓 ...

  4. Windows程序内部运行机制 转自http://www.cnblogs.com/zhili/p/WinMain.html

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  5. PHP的运行机制与原理(底层) [转]

    说到php的运行机制还要先给大家介绍php的模块,PHP总共有三个模块:内核.Zend引擎.以及扩展层:PHP内核用来处理请求.文件流.错误处理等相关操作:Zend引擎(ZE)用以将源文件转换成机器语 ...

  6. Chrome扩展开发之二——Chrome扩展中脚本的运行机制和通信方式

    目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...

  7. 深入浅出话VC++(1)——Windows程序内部运行机制

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  8. 基础知识《零》---Java程序运行机制及运行过程

    Java运行机制 Java虚拟机(Java Virtual Machine):Java虚拟机可以理解成一个以字节码为机器指令的CPU:对于不同的运行平台,有不同的虚拟机:Java虚拟机机制屏蔽了底层运 ...

  9. 【Linux下进程机制】从一道面试题谈linux下fork的运行机制

    今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #include "stdio.h" #includ ...

随机推荐

  1. 逆向-攻防世界-crackme

    查壳,nSpack壳,直接用软件脱壳,IDA载入程序. 很明显,就是将402130的数据和输入的数据进行异或,判断是否等于402150处的数据.dwrd占4字节. 这道题主要记录一下刚学到的,直接在I ...

  2. IIS虚拟目录挂载文件服务器目录

    要求说明: 通过网站上传文件保存到统一的文件服务器上. 服务器说明: 1.文件服务器以下称为FilesServer,IP地址为:192.168.1.213 2.Web服务器为以下称为WebServer ...

  3. php载入脚本的几种方式对比

    require require_once include include_once 共同点: 都可以在当前 PHP 脚本文件执行时载入另外一个 PHP 脚本文件. require 和 include ...

  4. Hadoop系列004-Hadoop运行模式(上)

    title: Hadoop系列004-Hadoop运行模式(上) date: 2018-11-20 14:27:00 updated: 2018-11-20 14:27:00 categories: ...

  5. 【Caffe篇】--Caffe从入门到初始及各层介绍

    一.前述 Caffe,全称Convolutional Architecture for Fast Feature Embedding.是一种常用的深度学习框架,主要应用在视频.图像处理方面的应用上.c ...

  6. 如何在ASP.NET Core程序启动时运行异步任务(3)

    原文:Running async tasks on app startup in ASP.NET Core (Part 3) 作者:Andrew Lock 译者:Lamond Lu 之前我写了两篇有关 ...

  7. JavaScript夯实基础系列(三):this

      在JavaScript中,函数的每次调用都会拥有一个执行上下文,通过this关键字指向该上下文.函数中的代码在函数定义时不会执行,只有在函数被调用时才执行.函数调用的方式有四种:作为函数调用.作为 ...

  8. Python实战171203统计

    统计序列中元素出现的频次 如何统计出某一个随机数列的元素出现的次数是多少? import randomdata=[random.randint(0,7) for _ in range(15)]c=di ...

  9. 搞懂MySQL InnoDB B+树索引

    一.InnoDB索引 InnoDB支持以下几种索引: B+树索引 全文索引 哈希索引 本文将着重介绍B+树索引.其他两个全文索引和哈希索引只是做简单介绍一笔带过. 哈希索引是自适应的,也就是说这个不能 ...

  10. Spring加载流程源码分析03【refresh】

      前面两篇文章分析了super(this)和setConfigLocations(configLocations)的源代码,本文来分析下refresh的源码, Spring加载流程源码分析01[su ...