《15天玩转WPF》—— 初步探索命令系统

我们知道激发事件与事件处理器是没有关联的,所以事件是不具有约束力的
命令与事件最大的区别就是,命令具有约束力
此文来实现一些简单的命令


文章目录


命令系统的一些概念

  1. 命令系统四要素:

    • 命令:实现 ICommand 接口的类
    • 命令源:命令的发送者,实现了 ICommandSouce 接口的类
    • 命令目标:命令作用的地方,实现了 IInputElement 接口的类
    • 命令关联:将一些外围逻辑与命令关联起来,执行前判断是否可以执行命令,
      后续工作有什么等
      (CommandBindings)
  2. RoutedCommand 命令类:
    由此类声明的命令是没有包含业务逻辑的,它的执行过程为:
    发出命令 --> 命令目标激发路由事件 --> 外围控件捕捉事件 --> 对命令目标加以处理(这句话贼重要!!!)


小试命令

实现这样一个需求:定义一个命令,使用 Button来发送这个命令,当命令送达 TextBox时 TextBox会被清空 (如果TextBox 中没有文字则命令不可被发送

  1. 程序XAML界面代码如下:
<Window x:Class="SmallCommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="175" Width="260" Background="LightBlue">
    <StackPanel x:Name="stackPanel">
        <Button x:Name="button1" Content="Send Command" Margin="5"/>
        <TextBox x:Name="textBoxA" Margin="5,0" Height="100"/>
    </StackPanel>
</Window>

效果如下:
在这里插入图片描述

  1. 后台逻辑部分:
  • 声明并定义命令(在MainWindow类中定义):
private RoutedCommand clearCmd = 
	new RoutedCommand("Clear", typeof(MainWindow));
  • 指定命令源并设置快捷键(在MainWindow类的构造器中):
this.button1.Command = this.clearCmd;
this.clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
  • 指定命令目标:
this.button1.CommandTarget = this.textBoxA; 
  • 创建命令关联:
CommandBinding cb = new CommandBinding();
cb.Command = this.clearCmd;
cb.CanExecute += Cb_CanExecute;
cb.Executed += Cb_Executed;
  • 将命令关联安置在外围控件上:
this.stackPanel.CommandBindings.Add(cb);	// 不放在外围控件上 将无法捕捉路由事件
  • 探测命令是否可以被执行(放在类中):
private void Cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
	// 判断TextBox中是否有东西
	if (string.IsNullOrEmpty(this.textBoxA.Text))
                e.CanExecute = false;
	else
                e.CanExecute = true;

	e.Handled = true;	// 避免继续上传降低程序性能	
}
  • 当命令送达目标后,此方法被调用(命令已经作用过了,激发此方法):
private void Cb_Executed(object sender, ExecutedRoutedEventArgs e)
{
	this.textBoxA.Clear();
	
	e.Handled = true;
}
  1. 效果动态图:

在这里插入图片描述

  1. 代码总结:

    命令可以判断Button是否,可以添加快捷键
    RoutedCommand 是一个与业务逻辑无关的类,上面对TextBox的 Clear是 CommandBinding干的事情.
    发出命令 --> 命令目标激发路由事件 --> 外围控件捕捉事件 --> 对命令目标加以处理
    我在上面写过这句话,理解了之后,就好办了 ^ _ ^&

  2. 示意图:

在这里插入图片描述


命令库的一些命令使用(XAML的使用)

有各种各样的常用的命令,微软在WPF中已经为我们准备好了,比如:
在这里插入图片描述

下面我们将来尝试使用这个命令,并且解决一个简单的小问题:

如果有两个相同的命令,我们希望他们干些不同的事,但命令的实例只有一个,我们该怎么办呢?

答案是使用 CommandPrameter,通过CommandPrameter的不同,来处理不同的信息

我们来实现一个用于处理相同命令但不同参数的例子,两个参数分别是 Teacher 和 Student,分别将它们存入 “档案”.

  1. XAML 部分(包含核心功能):
  • 将界面进行布局(分成七行):
<Window x:Class="SmallCommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="240" Width="360" Background="LightBlue"
         	WindowStyle="ToolWindow">
	<Grid Margin="6">
	<Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
	</Grid>
</Window>
  • 三个UI元素,TextBox用于输入信息,ListBox用于显示信息:
<TextBlock Text="Name:" VerticalAlignment="Center" HorizontalAlignment="Left"
 	Grid.Row="0"/>

<TextBox x:Name="nameTextBox" Margin="60,0,0,0" Grid.Row="0"/>

<ListBox x:Name="listBoxNewItems" Grid.Row="6"/>
  • 两个用于发出命令的Button,命令、命令参数:
<Button Content="New Teachar" Command="New" CommandParameter="Teachar" Grid.Row="2"/>
<Button Content="New Student" Command="New" CommandParameter="Student" Grid.Row="4"/>
  • 为窗体添加 CommandBinding,命令、两个事件方法:
<Window.CommandBindings>
        <CommandBinding  Command="New" CanExecute="CommandBinding_CanExecute" 
        	Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
  1. 后台实现两个路由事件处理器:
  • CommandBinding_CanExecute 方法:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
	if (string.IsNullOrEmpty(this.nameTextBox.Text)) // 判断需要输入的内容是否为空
		e.CanExecute = false;
	else
               	e.CanExecute = true;

	e.Handled = true;
}
  • CommandBinding_Executed 方法:
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
	string name = this.nameTextBox.Text;

	if (e.Parameter.ToString() == "Teachar")
                this.listBoxNewItems.Items.Add(string.Format("New Teacher: {0} , 
                	学而不厌,诲人不倦。", name));
                	
	if (e.Parameter.ToString() == "Student")
                this.listBoxNewItems.Items.Add(string.Format("New Student: {0} , 
                	好好学习,天天向上。", name));
}
  1. 效果动态图:

在这里插入图片描述


自定义命令

WPF命令系统并没有为我们准备重写命令方法的步骤
可以说 Commanding 是专门为 RouteCommand 而编写的。
所以我们自定义命令,需要完全的实现 命令、命令源、命令目标

我们需要实现这样一个功能:

  • 点击命令源,清除命令目标中的内容

命令的执行会直接调用命令目标的 Clear方法,用于清除里面的内容
如果我们没有Clear这个方法怎么办呢?

这里我就需要使用一个特定的接口来约束命令目标了

  1. 提供接口用于服务命令目标:
public interface IView
{
	void Clear();
}

里面也可以添加一些其它的逻辑,这里我为了方便,就只提供一个方法用于实现 …

  1. 自定义命令(继承于 ICommand):
public class ClearCommand : ICommand
{
	// 通过继承而来
	public event EventHandler CanExecuteChanged;

	// 为了方便,这个方法暂不实现
	public bool CanExecute(object parameter)
	{
		throw new NotImplementedException();
	}

	// 命令执行,与业务相关的 Clear逻辑
	public void Execute(object parameter)   // 这个参数是命令目标
	{
		IView view = parameter as IView;    
                
                if(view != null)
                {
                    view.Clear();       // 调用命令目标的 Clear方法,清除内容 
                }
	}
}

有了命令之后,我们需要一个命令源来 “发射” 它

  1. 自定义命令源(继承于 UserControl,ICommandSource):
public class MyCommandSource : UserControl, ICommandSource
{
	// 继承的属性
	public ICommand Command { get; set; }
	public object CommandParameter { get; set; }
	public IInputElement CommandTarget { get; set; }

	protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
	{
		base.OnMouseLeftButtonDown(e);
                
                if(this.CommandTarget != null)  // 命令目标存在
                {
                    this.Command.Execute(this.CommandTarget);
                }
	}
}
  1. 自定义控件,用于命令目标:
  • 创建项:
    在这里插入图片描述

  • XAML部分代码:
    在这里插入图片描述
    在这里插入图片描述

  • 为自定义控件的类实现 IView接口的方法:

在这里插入图片描述

  1. 程序主体 XAML部分,命令源的控件与命令目标的控件:
<Window x:Class="SmallCommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SmallCommand"

	Title="MainWindow" Height="205" Width="250" Background="LightBlue">

	<StackPanel>
        <local:MyCommandSource x:Name="ctrlClear" Margin="10">
            <TextBlock Text="清除" FontSize="16" TextAlignment="Center"
                       Background="LightGreen" Width="80"/>
	</local:MyCommandSource>

        <local:MyUserControl x:Name="miniView"/>

    </StackPanel>
    
</Window>

效果图:

在这里插入图片描述

当我们点击上面的清除时,下面四行的内容将被清除 …

  1. 后台指定命令实例、命令源、命令目标:
ClearCommand clearCommand = new ClearCommand();
this.ctrlClear.Command = clearCommand;
this.ctrlClear.CommandTarget = this.miniView;
  1. 效果动态图:

在这里插入图片描述


作者:浪子花梦

猜你喜欢

转载自blog.csdn.net/weixin_42100963/article/details/105139120
今日推荐