WPF中的命令模型
在WPF中,我们可以使用事件来响应鼠标和键盘动作。但使用事件会具备一定的局限性,例如:我想通过键盘快捷键触发事件、或者在某个时刻禁用事件。如果使用代码去编写这些控制逻辑,会变得非常枯燥。因此WPF提供了命令模型。
命令具有多个用途。 第一个用途是分隔语义和从执行命令的逻辑调用命令的对象。 这可使多个不同的源调用同一命令逻辑,并且可针对不同目标自定义命令逻辑。 例如,许多应用程序中均有的编辑操作“复制”、“剪切”和“粘贴”若通过使用命令来实现,那么可通过使用不同的用户操作来调用它们。 应用程序可允许用户通过单击按钮、选择菜单中的项或使用组合键(例如 Ctrl+X)来剪切所选对象或文本。 通过使用命令,可将每种类型的用户操作绑定到相同逻辑。
命令的另一用途是指示操作是否可用。 继续以剪切对象或文本为例,此操作只有在选择了内容时才会发生作用。 如果用户在未选择任何内容的情况下尝试剪切对象或文本,则不会发生任何操作。 为了向用户指示这一点,许多应用程序通过禁用按钮和菜单项来告知用户是否可以执行某操作。 命令可以通过实现 CanExecute 方法来指示操作是否可行。 按钮可以订阅 CanExecuteChanged 事件,如果 CanExecute 返回 false
则禁用,如果 CanExecute 返回 true
则启用。
通俗点来说,命令模型就是事件的“升级版本”,
它可以让多个不同的源调用同一个逻辑
例如我一有个打印功能,我们将它封装成PrintDocument,当在菜单选择时、按钮点击时、快捷键按下时,我们都去执行这个功能。
它还可以控制这个功能是否可以被执行,例如,我当前未选中要打印的文档,我设置CanExecute 方法返回false,打印功能是无法被执行的。当选中了要打印的文档,设置CanExecute 方法返回true,这时候,打印功能又可以被执行了。
WPF 命令中的四个主要概念
WPF中的命令模型可分解为四个主要概念:命令、命令源、命令目标和命令绑定:
-
命令:要执行的操作。
-
命令源:调用命令的对象。
-
命令目标:在其上执行命令的对象。
-
命令绑定:将命令逻辑映射到命令的对象。
命令
命令表示应用程序任务,并且跟踪任务是否能够被执行。然而,命令实际上不包含执行应用程序任务的代码。
命令绑定
每个命令绑定针对用户界面的具体区域,将命令连接到相关的应用程序逻辑。这种分解的设计是非常重要的,因为单个命令可用于应用程序中的多个地方,并且在每个地方具有不同的意义。为处理这一问题,需要将同一命令与不同的命令绑定。
命令源
命令源触发命令。例如,Menultem和 Button都是命令源。单击它们都会执行绑定命令。
命令目标
命令目标是在其中执行命令的元素。例如,Paste命令可在TextBox控件中插入文本,而OpenFile命令可在 DocumentViewer 中打开文档。根据命令的本质,目标可能很重要,也可能不重要。
注意:如果对于这些基础概念理解起来有困难,可以先暂时跳过,直接学习后面的部分。等掌握以后,再回头来看这些基础概念。
MVVM中的快速示例
在前面的文章中,我们学习了数据绑定,可以在DataContext中,取到界面上的值。如果我们需要在DataContext(ViewModel层)去响应控件的事件,就需要用到Command。
假设有如下界面,我们想在点击按钮后,弹框输出文本框的值。
1 <StackPanel> 2 <Label Content="输入"></Label> 3 <TextBox Name="tbox"></TextBox> 4 5 <Button Content="获取输入"></Button> 6 </StackPanel>
在WPF的基于事件模式的开发中,一般会响应按钮的Click事件
1 <Button Content="获取输入" Click="Button_Click"></Button>
然后在后台代码中对事件进行处理
1 private void Button_Click(object sender, RoutedEventArgs e) 2 { 3 MessageBox.Show(this.tbox.Text); 4 }
在MVVM模式开发中,我们会直接绑定到一个命令
1 <StackPanel> 2 <Label Content="输入"></Label> 3 <TextBox Text="{Binding InputText}"></TextBox> 4 5 <Button Content="获取输入" Command="{Binding GetInputCommand}"></Button> 6 </StackPanel>
在ViewModel中对命令进行处理
1 public class MainWindowViewModel 2 { 3 public ICommand GetInputCommand { get; private set; } 4 5 public MainWindowViewModel() 6 { 7 GetInputCommand = new RelayCommand(GetInput); 8 } 9 10 public void GetInput() 11 { 12 MessageBox.Show(InputText); 13 } 14 }
运行效果
接下来详细介绍一下,如何在MVVM中使用命令模型。
ICommand接口