WPF学习—命令

摘抄自《深入浅出WPF》第九章

WPF命令系统基本要素:

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

2.命令源(Command Source):命令发送者,是实现了ICommandSource接口的类

3.命令目标(Command Target):命令发送目标。命令目标必须是实现了IInputElement接口的类

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

命令的使用步骤:

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

2.声明命令实例:创建命令类的实例

3.指定命令源:即指定由谁发送命令。一旦把命令指派给命令源,命令原会受命令的影响,当命令不能被执行的时候作为命令源的控件将处在不可用的状态。

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

5.设置命令关联:WPF命令需要CommandBindng在执行前来帮助判断是不是可以执行,在执行后还要做一些事件。

WPF命令系统基本元素关系图:

实例:定义一个命令,使用Button发送,命令送达TextBox时TextBox会被清空(如果TextBox中没有文字则命令不可被送达,Button按钮不可用)

XAML界面:

<Window x:Class="SimpleCommandTest.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:SimpleCommandTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel x:Name="stackPanel" Margin="5" Background="AliceBlue">
            <Button x:Name="button1" Content="Send Command" Margin="5"/>
            <TextBox x:Name="textBoxA" Margin="5" Height="100" TextWrapping="Wrap"/>
        </StackPanel>
    </Grid>
</Window>

后台代码:

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            InitializeCommand();
        }
        //声明并定义命令
        private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(MainWindow));

        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 = this.clearCmd;
            cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);
            cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
            //把命令关联安置在外围控件上
            this.stackPanel.CommandBindings.Add(cb);
        }

        //当探测命令是否可以执行时,调用
        void cb_CanExecute(object sender,CanExecuteRoutedEventArgs e)
        {
            if(string.IsNullOrEmpty(this.textBoxA.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
            e.Handled = true;
        }

        //命令送达目标后,调用
        void cb_Executed(object sender,ExecutedRoutedEventArgs e)
        {
            this.textBoxA.Clear();
            e.Handled = true;
        }
    }

WPF命令库:

1.ApplicationCommands

2.ComponentCommands

3.NavigationCommands

4.MediaCommands

5.EditingCommands

带参数的命令:通过参数来决定命令要做什么事。命令源一定是实现了ICommandSource接口的对象,而ICommandSource有一个名为CommandPrameter的属性。

实例:

XAML代码

<Window x:Class="SimpleCommandPrameterTest.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:SimpleCommandPrameterTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="5" Background="AliceBlue">
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4">
            </RowDefinition>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <TextBlock Text="Name:" VerticalAlignment="Center" HorizontalAlignment="Left" />
        <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>
    <!--为窗口添加CommandBinding-->
        <Window.CommandBindings>
        <CommandBinding Command="New" CanExecute="New_CanExecute" Executed="New_Executed"/>
    </Window.CommandBindings>
</Window>

后台代码:

 public MainWindow()
        {
            InitializeComponent();
        }

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

        private void New_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            string name = this.nameTextBox.Text;
            if(e.Parameter.ToString()=="Teacher")
            {
                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));
            }
            this.nameTextBox.Clear();
        }
    }

在XAML中定义了命令不同的参数,参数不同命令执行后结果不同。

自定义命令

首先创建一个WPF工程,在MainWindow.xaml.cs中定义一个接口:

public interface IView
    {
        bool IsChanged { get; set; }

        void SetBinding();
        void Refresh();
        void Clear();
        void Save();
    }

每个需要接受命令的组件必须实现这个接口,确保命令可以成功地对它们执行操作

实现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();
            }
        }

    }

命令实现了ICommand接口并继承了CanExecuteChanged事件、CanExecute方法和Execute方法。此命令只用到了Execute方法,实现这个方法时,将方法的参数作为命令的目标,如果目标是IView接口派生类,则调用Clear方法

通过实现ICommandSource接口创建自定义命令源:

 public class MyCommandSource : UserControl, ICommandSource
    {
        //继承自ICommandSource的三个属性
        public ICommand Command { get; set; }
        public object CommandParameter { get; set; }
        public IInputElement CommandTarget { get; set; }

        //组件被单击时连带执行命令
        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseLeftButtonDown(e);
            //在命令目标上执行命令,或称让命令作用于命令目标
            if (this.CommandTarget != null)
            {
                this.Command.Execute(this.CommandTarget);
            }
        }
    }

ICommandSource接口包含Command、CommandParameter、CommandTarget三个属性。在此,CommandParameter没有用到,而CommandTarget被当做参数传递给了Command的Execute方法。

创建命令目标:因为ClearCommand命令作用于IView派生类,所以命令目标必须实现IView接口。为工程添加一个用户控件(UserControl)

XAML代码如下:

<UserControl x:Class="UserCommandTest.MiniView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:UserCommandTest"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <TextBox x:Name="textBox1" Margin="5"/>
        <TextBox x:Name="textBox2" Margin="5"/>
        <TextBox x:Name="textBox3" Margin="5"/>
        <TextBox x:Name="textBox4" Margin="5"/>
    </StackPanel>
</UserControl>

后台代码如下(此类需要继承自IView):

//此类需要继承IView
    public partial class MiniView : UserControl,IView
    {
        public MiniView()
        {
            InitializeComponent();
        }

        public bool IsChanged { get; set; }
        public void SetBinding(){ }
        public void Refresh() { }
        public void Save() { }

        public void Clear()
        {
            this.textBox1.Clear();
            this.textBox2.Clear();
            this.textBox3.Clear();
            this.textBox4.Clear();
        }
    }

主窗体的XAML代码:

<Window x:Class="UserCommandTest.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:UserCommandTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <local:MyCommandSource x:Name="ctrlClear" Margin="10">
                <TextBlock Text="清除" FontSize="16" TextAlignment="Center" Background="LightGreen" Width="80"/>
            </local:MyCommandSource>
            <local:MiniView x:Name="miniView"/>
        </StackPanel>
    </Grid>
</Window>

主窗体后台代码:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            ClearCommand clearCmd = new ClearCommand();
            this.ctrlClear.Command = clearCmd;
            this.ctrlClear.CommandTarget = this.miniView;
        }
    }

先创建一个ClearCommand命令实例,并赋值给自定义命令源的Command属性,自定义命令源的CommandTarget属性是自定义命令目标MiniView实例。

原文地址:https://www.cnblogs.com/mengjiulong/p/9800624.html

时间: 2024-08-05 00:47:26

WPF学习—命令的相关文章

命令——WPF学习之深入浅出

WPF学习之深入浅出话命令 WPF为我们准备了完善的命令系统,你可能会问:“有了路由事件为什么还需要命令系统呢?”.事件的作用是发布.传播一些消息,消息传达到了接收者,事件的指令也就算完成了,至于如何响应事件送来的消息事件并不做任何限制,每个接收者可已用自己的行为来响应事件.也就是说,事件不具有约束力.命令和事件的区别就在于命令具有约束力. 的确,在实际编程工作中,即使只用事件不用命令程序的逻辑一样被驱动的很好,但我们不能够阻止程序员按照自己的习惯去编写代码.比如保存事件的处理器,程序员可以写S

【WPF学习】第三十二章 执行命令

原文:[WPF学习]第三十二章 执行命令 前面章节已经对命令进行了深入分析,分析了基类和接口以及WPF提供的命令库.但尚未例举任何使用这些命令的例子. 如前所述,RoutedUICommand类没有任何硬编码的功能,而是只表达命令,为触发命令,需要有命令源(也可使用代码).为响应命令,需要有命令绑定,命令绑定将执行转发给普遍的事件处理程序. 一.命令源 命令库中的命令始终可用.触发他们的最简单的方法是将它们关联到实现了ICommandSource接口的控件,其中包括继承自ButtonBase类的

【WPF学习】第三十一章 WPF命令模型

原文:[WPF学习]第三十一章 WPF命令模型 WPF命令模型由许多可变的部分组成.总之,它们都具有如下4个重要元素: 命令:命令表示应用程序任务,并且跟踪任务是否能够被执行.然而,命令实际上不包含执行应用程序任务的代码. 命令绑定:每个命令绑定针对用户界面的具体区域,将命令连接到相关的应用程序逻辑.这种分解的设计是非常重要的,因为单个命令可用于应用程序中的多个地方,并且在每个地方具有不同的意义.为处理这一问题,需要将同一命令与不同的命令绑定. 命令源:命令源触发命令.例如,MenuItem和B

WPF C# 命令 学习

1.概述 1.1 WPF C# 命令的本质 命令是 WPF 中的输入机制,它提供的输入处理比设备输入具有更高的语义级别. 例如,在许多应用程序中都能找到的“复制”.“剪切”和“粘贴”操作就是命令. WPF 中的命令是通过实现 ICommand 接口创建的. ICommand 的 WPF 实现是 RoutedCommand 类,这是WPF C# 命令的本质. 1.2 WPF C# 命令的机制 1.2.1 编程范围 ICommand 公开两个方法(Execute 及 CanExecute)和一个事件

WPF学习07:MVVM 预备知识之数据绑定

MVVM是一种模式,而WPF的数据绑定机制是一种WPF内建的功能集,两者是不相关的. 但是,借助WPF各种内建功能集,如数据绑定.命令.数据模板,我们可以高效的在WPF上实现MVVM.因此,我们需要对各种MVVM相关的WPF内建功能集进行了解,才能在扎实的基础上对MVVM进行学习与实践. 本文是WPF学习03:Element Binding的后续,将说明实现数据绑定的三个重点:DataContext INotifyPropertyChanged IValueConverter MVVM简介 MV

WPF学习08:MVVM 预备知识之COMMAND

WPF内建的COMMAND是GOF 提出的23种设计模式中,命令模式的实现. 本文是WPF学习07:MVVM 预备知识之数据绑定的后续,将说明实现COMMAND的三个重点:ICommand  CommandManager InputBindings COMMAND简介 一般情况我们应用设计如下,一个个控件的各类Handler直接关心了如何实现具体的应用逻辑. 借助COMMAND,我们将具体实现的应用逻辑放在COMMAND中实现,控件只需要绑定相应的COMMAND,而无需关心应用逻辑,从而实现界面

WPF学习11:基于MVVM Light 制作图形编辑工具(2)

本文是WPF学习10:基于MVVM Light 制作图形编辑工具(1)的后续 这一次的目标是完成 两个任务. 画布 效果: 画布上,选择的方案是:直接以Image作为画布,使用RenderTargetBitmap绑定为Image的图片源,这样可以为后续的导出图片功能提供很大的便利. 对拖动栏XAML进行如下修改: <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="

【WPF学习】第二十章 内容控件

原文:[WPF学习]第二十章 内容控件 内容控件(content control)是更特殊的控件类型,它们可包含并显示一块内容.从技术角度看,内容控件时可以包含单个嵌套元素的控件.与布局容器不同的是,内容控件只能包含一个子元素,而布局容器主要愿意可以包含任意多个牵头元素. 正如前面所介绍,所有WPF布局容器都继承自抽象类Panel,该类提供了对包含多个元素的支持.类似地,所有内容控件都继承自抽象类ContentControl.下图显示了ContentControl类的层次结构. 图 Conten

WPF之命令浅谈

一.认识命令 1.1命令的特点 提到“命令”,我们应该想到命令的发出者,命令的接受者,命令的内容,准备工作,完成任务,回报工作...与事件中的发送者,接受者,消息,处理,处理,处理一一对应,如果是单纯的几个对应关系,的确用事件是能够代替的,不过,命令相对事件有其自己的特点的.比如,古时候,如果两个部落发动战争,经常在出军之前,做了充分的准备,才可能一声令下,冲啊!相反,如果没有准备好的话,一定会限制,军队不能随意出军,所以命令具有限制性.除此之外,命令一旦下达是不经常更改的.如在软件里面,一般C