深入浅出WPF——命令

深入浅出WPF——命令事件的作用是发布、传播一些消息,消息送达接收者,事件的使命也就完成了,至于如何响应事件送来的消息事件并不做规定,每个接收者可以使用自己的行为来响应事件。也就是说,事件不具有约束力。命令与事件的区别就在于命令具有约束力。1:命令系统的基本元素与关系…

大家好,欢迎来到IT知识分享网。

事件的作用是发布、传播一些消息,消息送达接收者,事件的使命也就完成了,至于如何响应事件送来的消息事件并不做规定,每个接收者可以使用自己的行为来响应事件。也就是说,事件不具有约束力。命令与事件的区别就在于命令具有约束力。

1:命令系统的基本元素与关系

1:命令系统的基本元素

WPF的命令系统由几个基本要素构成:

(1)命令(Command):WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类。

(2)命令源(Command Source):即命令的发送者,是实现了ICommandSource接口的类。很多界面元素都是实现了这个接口,其中包括Button、MenuItem、ListBoxItem等。

(3)命令目标(Command Target):即命令将发送给谁,或者说命令将作用在谁身上。命令目标必须是实现了IInputElement接口的类。

(4)命令关联(Command Binding):负责把一些外围逻辑与命令关联在一起。

2:基本元素之间的关系

这些基本元素之间的关系体现在使用的命令过程中。命令的使用大概分为如下几步:

(1):创建命令类:即获得一个实现ICommand接口的类,如果命令与具体业务逻辑无关则使用WPF类库中的RoutedCommand类即可。如果想得到与业务逻辑相关的专有命令,则需要创建RoutedCommand的派生类。

(2)声明命令实例:使用命令时需要创建命令类的实例。

(3)指定命令源:即指定由谁来发送这个命令。

(4)指定命令目标:命令目标并不是命令的属性而是命令源的属性,指定命令目标是告诉命令源向哪个组件发送命令,无论这个组件是否拥有焦点它都会收到这个命令。如果没有为命令源指定命令目标,则WPF系统认为当前拥有焦点的对象就是命令目标。

(5)设置命令关联:WPF命令需要CommandBinding在执行前来帮助判断是不是可以执行、在执行后做一些事件。

在命令目标和命令关联之间还有个微妙的关系。无论命令目标是由程序员指定还是有WPF系统根据焦点所在地判断出来的,一旦某个UI组件被命令“瞄上”,命令源就会不停地向命令目标“投石问路”,命令目标就会不停地发送出可路由的PreviewCanExecute和CanExecute附加事件,事件会沿着UI元素树向上传递并被命令关联所捕捉,命令关联捕捉到这些事件后会把命令能不能发送实时报告给命令。类似的,如果命令被发送出来并到达命令目标,命令目标就会发送PreviewExecuted和CanExecuted两个附加事件,这两个事件也会沿着UI元素树向上传递并被命令关联所捕捉,命令关联会完成一些后续的任务。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Height="350" Width="525">
    <StackPanel x:Name="stackPanel">
        <Button x:Name="button1" Content="send Command" Margin="5"/>
        <TextBox x:Name="textBoxA" Margin="5,0" Height="100"/>
    </StackPanel>
</Window>
namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            InitializeCommand();
        }
        //声明并定义命令
        private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(Window));
        private void InitializeCommand()
        {
            //把命令赋给命令源并指定快捷键
            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 = clearCmd;
            cb.CanExecute += new CanExecuteRoutedEventHandler(Cb_CanExecute);
            cb.Executed += new ExecutedRoutedEventHandler(cb_Execute);
            //把命令关联安置在外围控件上
            this.stackPanel.CommandBindings.Add(cb);
        }

        private void cb_Execute(object sender, ExecutedRoutedEventArgs e)
        {
            this.textBoxA.Clear();
            e.Handled = true;
        }

        private void Cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(this.textBoxA.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
            e.Handled = true;
        }
    }
}

使用命令可以避免自己写代码判断Button是否可用以及添加快捷键;RoutedCommand是一个与业务无关的类,只负责在程序中“跑腿”而并不对命令目标做任何操作;因为CanExecute事件激发频率比较高,为了避免降低性能,在处理完后建议把e.Handler设为true;CommandBinding一定要这是在命令目标的外围控件上,不然无法捕捉到CanExecute和Executed等路由事件。

4:WPF的命令库

命令具有“一处声明、处处使用”的特点,微软在WPF类库里准备了一些便捷的命令库。

(1)ApplicationCommands

(2)ComponentCommands

(3)NavigationCommands

(4)MediaCommands

(5)EditingCommands

它们都是静态类,而命令就是用这些类的静态只读属性以单件模式暴露出来的。

5:命令参数

命令源一定是实现了ICommandSource接口的对象,而ICommandSource有一个属性就是CommandPrameter,如果把命令看做飞向目标的炮弹,那么CommandPrameter就相当于装载在炮弹里的“消息”。

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.CommandBindings>
        <CommandBinding Command="New" CanExecute="New_CanExecute" Executed="New_Executed"/>
    </Window.CommandBindings>
    <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>
        <TextBlock Text="Name:" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="0"/>
        <TextBox x:Name="nameTextBox" Margin="60,0,0,0" Grid.Row="0"/>
        <Button Content="New Teacher" Command="New" CommandParameter="Teacher" Grid.Row="2"/>
        <Button Content="New Student" Command="New" CommandParameter="Student" Grid.Row="4"/>
        <ListBox x:Name="listBoxNewItems" Grid.Row="6"/>
    </Grid>
</Window>
namespace WpfApplication2
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void New_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            string name = this.nameTextBox.Text;
            if (e.Parameter.ToString() == "Teacher")
            {
                this.listBoxNewItems.Items.Add(string.Format("Teacher {0},好好学习", name));
            }
            if (e.Parameter.ToString() == "Student")
            {
                this.listBoxNewItems.Items.Add(string.Format("Student {0},天天向上", name));
            }
        }

        private void New_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(this.nameTextBox.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
            e.Handled = true;
        }
    }
}

6:命令与Binding的结合

控件有很多事件,可以让我们进行各种各样的操作,可控件只有一个Command属性、而命令库中却有数十种命令,这样怎么可能使用这个唯一Command属性来调用那么多的命令呢?答案是:使用Binding。

2:近观命令

一般情况下,程序中使用与逻辑无关的RoutedCommand来跑跑龙套就足够了,但为了使程序的结构更加简洁,我们常需要定义自己的命令。

1:ICommand接口与RoutedCommand

WPF的命令是实现了ICommand接口的类。ICommand接口非常简单,只包含两个方法和一个事件:

(1)Execute方法:命令执行,或者说命令作用于命令目标之上。

(2)CanExecute方法:在执行之前用来探知命令是否可被执行。

(3)CanExecuteChanged事件:当命令可执行状态发生改变时,可激发此事件来通知其他对象。

RoutedCommand就是这样一个实现了ICommand接口的类。RoutedCommand在实现ICommand接口时,并未向Execute和CanExecute方法中添加任何逻辑,也就是说,它是通用的、与具体业务逻辑无关。

2:自定义Command

WPF自带的命令源和CommandBinding就是专门为RoutedCommand而编写的,如果我们想要使用自己的ICommand派生类就必须连命令源一起实现。

 

参考教材书:深入浅出WPF 刘铁猛  著

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/10933.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信