WPF内建的COMMAND是GOF 提出的23种设计模式中,命令模式的实现。
本文是WPF学习07:MVVM 预备知识之数据绑定的后续,将说明实现COMMAND的三个重点:ICommand CommandManager InputBindings
一般情况我们应用设计如下,一个个控件的各类Handler直接关心了如何实现具体的应用逻辑。
借助COMMAND,我们将具体实现的应用逻辑放在COMMAND中实现,控件只需要绑定相应的COMMAND,而无需关心应用逻辑,从而实现界面与应用逻辑的解耦。
WPF内建的COMMAND除了提供了逻辑解耦外,还可以用来实现控件使能管理、命令的历史记录(使操作可撤销)。
本文将介绍如何在MVVM下运用COMMAND,以及控件的使能管理。历史记录功能将在下篇学习笔记中再介绍。
由CheckBox 管理Command是否可以被执行,Ctrl + A与按键被按均能执行同样的业务逻辑。
XAML代码:
<Window x:Class="Commands.CommandBlog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="CommandBlog" Height="300" Width="300"> <Window.InputBindings> <KeyBinding Key="A" Modifiers="Control" Command="{Binding NewFile}"></KeyBinding> </Window.InputBindings> <StackPanel Background="White"> <Button Command="{Binding NewFile}">New file</Button> <CheckBox IsChecked="{Binding NewFileEnable}" HorizontalAlignment="Center">New file Function Enable</CheckBox> </StackPanel> </Window>
界面部分后台代码,只需要配置DataContext即可:
public partial class CommandBlog : Window { public CommandBlog() { InitializeComponent(); DataContext = new CommandBlogViewModel(); } }
CommandBlogViewModel:
class CommandBlogViewModel:INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public ICommand NewFile { get; private set; } public CommandBlogViewModel() { NewFile = new NewFileCommand(this); } private Boolean newFileEnable; public Boolean NewFileEnable { get { return newFileEnable; } set { newFileEnable = value; if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("NewFileEnable")); } } }
NewFileCommand:
class NewFileCommand : ICommand { private CommandBlogViewModel commandBlogViewModel; public NewFileCommand(CommandBlogViewModel commandBlogViewModel) { this.commandBlogViewModel = commandBlogViewModel; } public bool CanExecute(object parameter) { return this.commandBlogViewModel.NewFileEnable; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Execute(object parameter) { MessageBox.Show("New"); } }
// Summary: // Occurs when changes occur that affect whether or not the command should execute. event EventHandler CanExecuteChanged; // Summary: // Defines the method that determines whether the command can execute in its // current state. bool CanExecute(object parameter); // Summary: // Defines the method to be called when the command is invoked. void Execute(object parameter);
CanExecute与Execute的意思都很明显,可以在刚才的例子中看出来。这里重点介绍一下如何给它们传参。
我们可以通过设置CommandParameter向两者传参:
例子:
<!--主窗体起名为MainWindow--> <Button Command="{Binding NewFile}" CommandParameter="{Binding ElementName=MainWindow}">New file</Button>
public void Execute(object parameter) { var inputElement = parameter as IInputElement; if (inputElement!= null) { var pos = Mouse.GetPosition(inputElement); } }
为了使WPF能够自动识别CanExecute的变化,我们需要手动对CanExecuteChanged加以下代码:
public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } }
当我们希望可以自定义命令的输入映射时,需要用到InputBindings:
例子:
<Window.InputBindings> <KeyBinding Key="A" Modifiers="Control" Command="{Binding NewFile}"></KeyBinding> <KeyBinding Key="C" Modifiers="Control" Command="{Binding CopyContent}"></KeyBinding> <KeyBinding Key="V" Modifiers="Control" Command="{Binding PasteContent}"></KeyBinding> <KeyBinding Key="F1" Modifiers="Control" Command="{Binding HelpPrompt}"></KeyBinding> </Window.InputBindings>