自定义命令,可以分为两个层次来理解
1.声明自己的RoutedCommand实例,这个层次比较浅
2.从实现ICommand接口开始,这个才算的上真正的自定义命令
自定义命令的目的是为了把业务逻辑转移到命令内部,而不是需要捕捉到命令之后再回过头去处理。
要想自定义命令,就不能不了解命令系统的几个要素:
1.命令(Command):WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的就是RoutedCommand类.
2.命令源(Command Source):命令的发送者,是实现了ICommandSource的类,平时用的Button就实现了这个接口
3.命令目标(Command Target):即命令将发送给谁,或者说命令的作用对象,是实现了IINputElement的类
4.命令关联(Command Binding):负责把一些外围逻辑与命令关联起来,比如执行之前对命令是否可以执行进行判断,命令执行之后还有那些后续工作
了解了命令系统的几个要素,就可以自己定义命令了
1.定义接口
为了规范我们的命令源,更统一的通过命令来调用,我们约定一个接口,所有使用该命令的命令源必须是实现了该接口的类型。
interface IView { //是否更改 bool IsChanged { get; set; } //方法 void SetBinding(); void Refresh(); void Clear(); void Save(); }
2.定义命令
创建一个专门用于处理IView接口派生类的命令。我们说,命令就是实现了ICommand接口的类,接口包含两个方法,一个委托事件,我们这里只实现Excute方法
class ClearCommand:ICommand { public bool CanExecute(object parameter) { throw new NotImplementedException(); } public event EventHandler CanExecuteChanged; public void Execute(object parameter) { IView view = parameter as IView; //这里体现了我们的业务逻辑 view.Clear(); } }
3.定义命令源
有了命令,下一步定义发送命令的命令源
class MyCommandSource:UserControl,ICommandSource { //命令 public ICommand Command{ get;set; } //参数 public object CommandParameter { get; set; } //目标 public System.Windows.IInputElement CommandTarget { get; set; } protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); //执行命令 if (this.Command != null) { //目标作为参数 Command.Execute(this.CommandTarget); } } }
4.定义命令的目标
命令目标有两个限制,一个是实现IInputElement,另一个是我们定义的,要求实现接口IView
分为两部分 一部分是XAML
<UserControl x:Class="CommandTest2.MiniView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="120" Width="200"> <Grid> <Border CornerRadius="5" BorderBrush="LawnGreen" BorderThickness="2"> <StackPanel> <TextBox x:Name="txt1" Margin="5"></TextBox> <TextBox x:Name="txt2" Margin="5"></TextBox> <TextBox x:Name="txt3" Margin="5"></TextBox> <TextBox x:Name="txt4" Margin="5"></TextBox> </StackPanel> </Border> </Grid> </UserControl>
另一部分是后台代码
namespace CommandTest2 { /// <summary> /// MiniView.xaml 的交互逻辑 /// </summary> public partial class MiniView : UserControl,IView { public MiniView() { InitializeComponent(); } public bool IsChanged { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public void SetBinding() { throw new NotImplementedException(); } public void Refresh() { throw new NotImplementedException(); } public void Save() { throw new NotImplementedException(); } public void Clear() { txt1.Clear(); txt2.Clear(); txt3.Clear(); txt4.Clear(); } } }
这样,我们需要的几个部分凑齐,就可以使用了
窗体代码
<Window x:Class="CommandTest2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CommandTest2" Title="Command" Height="205" Width="250"> <StackPanel> <local:MyCommandSource x:Name="ctrlClear" Margin="10"> <TextBlock Text="清除" FontSize="16" TextAlignment="Center" Background="LightGreen" Width="80"></TextBlock> </local:MyCommandSource> <local:MiniView x:Name="miniView"></local:MiniView> </StackPanel> </Window>
后台调用也很简单
ClearCommand clrCommand = new ClearCommand(); ctrlClear.Command = clrCommand; ctrlClear.CommandTarget = miniView;
参考《深入浅出WPF》刘铁猛 第9章
ps.工作需要,开始学习WPF,感觉跟ASP.NET还是有很多不一样的,在这里记录一下学习的历程,以便今后回顾之用,看如何一步步走的,走向何方