在本系列的第1部分中,Eric Voge引导你通过设计模式,处理常用的UI交互。
命令模式是一种通用的软件设计模式,让您轻松封装推迟执行方法所需的逻辑。它通常用于使用统一方式处理控件动作。
该模式包括三个角色:客户端,调用者和一个接收者。客户端是负责创建一个具体的命令,并为执行提供其输入数据。调用者确定何时执行该命令。接收者是需要执行命令动作的类。通常情况下,接收类执行命令的方法或调用对象的构造函数。
命令模式非常适用于处理GUI交互。它已经已经被微软紧密的融入了Windows Presentation Foundation(WPF)堆栈。最重要的一条是ICommand接口位于System.Windows.Input命名空间。任何实现了ICommand接口的了,都可以用来处理常见WPF控件的键盘或鼠标事件。这种连接可以写在XAML或后台代码中。
ICommand接口需要的CanExecute和Execute方法,以及CanExecuteChanged 事件来处理可执行状态的变化:
public interface ICommand { event EventHandler CanExecuteChanged; bool CanExecute(object parameter); void Execute(object parameter); }
MessageBoxCommand类
接下来,您创建一个具体的命令,将它链接到一个控件动作。自定义命令将显示一个消息框传递给用户。在构造函数中,接收者类作为构造参数。检查看接收者类是否实现了INotifyPropertyChanged接口并且接收了PropertChanged事件。在 PropertyChanged事件添加处理程序,触发CanExecuteChanged强制CanExecute方法进行重新评估。在CanExecute方法中实现,只有传递一个非空参数才允许执行命令。最后,在执行方法中,消息框将显示参数的内容。看到完整的源代码清单1。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Input; using System.ComponentModel; namespace VSMCommandPatternDemo.Commands { public class MessageBoxCommand : ICommand { private object _receiver; public MessageBoxCommand() { } public MessageBoxCommand(object receiver) { _receiver = receiver; if (_receiver as INotifyPropertyChanged != null) { INotifyPropertyChanged propChanged = _receiver as INotifyPropertyChanged; propChanged.PropertyChanged += new PropertyChangedEventHandler(propChanged_PropertyChanged); } } void propChanged_PropertyChanged(object sender, PropertyChangedEventArgs e) { CanExecuteChanged(this, e); } public bool CanExecute(object parameter) { return parameter != null; } public event EventHandler CanExecuteChanged; public void Execute(object parameter) { if(parameter != null) MessageBox.Show(parameter.ToString()); } } }
接下来,将这个命令链接到一个真正的应用程序。创建一个名为VSMCommandPatternDemo C#WPF应用程序。然后,创建一个Commands文件夹,并给它添加MessageBoxCommand类。现在,您可以添加视图模型类,其中将包含将绑定到UI的ICommand和MyMessage属性。在项目中添加名为MessageViewModel类。类也实现了INotifyPropertyChanged接口为MyMessage属性。看到完整的源代码清单2。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Windows.Input; namespace VSMCommandPatternDemo { public class MessageViewModel : INotifyPropertyChanged { private string _myMessage; public string MyMessage { get { return _myMessage; } set { if (_myMessage != null) { PropertyChanged(this, new PropertyChangedEventArgs("MyMessage")); } _myMessage = value; } } public ICommand MessageBoxCommand { get; set; } public event PropertyChangedEventHandler PropertyChanged; public MessageViewModel() { MessageBoxCommand = new Commands.MessageBoxCommand(this); } } }
用户界面标记
下一步,您可以添加UI标记。该应用程序包含输入消息的textbox和一个名为Say的button用来调用消息框。打开MainWindow.xaml,插入根的<Grid>元素下面的标记:
<StackPanel x:Name="MessageStack"> <Label>Message</Label> <TextBox x:Name="Message" Text="{Binding Path=MyMessage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox> <Button x:Name="Say" CommandParameter="{Binding Path=MyMessage}" Command="{Binding Path=MessageBoxCommand}">Say</Button> </StackPanel>
Message文本框设置为双向绑定,设置UpdatedSourceTrigger关联PropertyChanged,当文本改变时触发绑定事件。默认情况下文本框只有触发了LostFocus事件才执行绑定行为。CommandParameter和Command属性用于在sayanniu上绑定自定义命令。 CommandParameter绑定到视图模型的MyMessage属性,并讲Command属性绑定到MessageBoxCommand属性。 MainWindow的形式全面标记。
现在,所有剩下要做的就是将MessageViewModel绑定MainWindow窗体。打开的MainWindow.xaml.cs类的定义,并讲窗体的DataContext赋值为MessageViewModel的实例如下:
this.DataContext = new MessageViewModel();
完整的 MainWindow 类代码如下:
using System; using System.Windows; namespace VSMCommandPatternDemo { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MessageViewModel(); } } }
现在可以运行这个程序了,在文本框中输入一条信息,点击say按钮,如下图所以运行界面:
总结:
Command模式是一个很好的方式来分离UI和业务逻辑。它能让你的视图、后台代码保持整洁、灵活。可以轻松的更换需要执行的命令或者多个控件事件绑定相同的命令。Command更伟大之处在于处理Undo系统,将在本系列第二部分演示。
原文地址:http://visualstudiomagazine.com/articles/2012/04/10/command-pattern-in-net.aspx