【WPF】命令 --《深入浅出WPF》

命令使用步骤:

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

声明命令实例。使用命令时需要创建命令类的实例。一般情况下,程序中的某种操作只需要一个命令实例与之对应即可,因此,程序中的命令多使用单件模式,以减少代码复杂度。

指定命令的源。同一个命令可以有多个源,一旦命令指派给命令源,那么命令源就会受命令的影响,当命令不能被执行的时候,作为命令源的控件将处于不可用的状态。

指定命令的目标。命令目标不是命令的属性,而是命令源的属性,被指定为命令源的组件,无论是否拥有焦点都会收到命令。如果没有指定目标,wpf默认当前拥有焦点的对象就是命令目标。

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

一、RoutedCommand

 

 前端代码:

     <StackPanel Name="clearStackPanel">
        <StackPanel Orientation="Horizontal">
            <Button Name="clearButton" Content="Send Clear Text Command" Margin="5" />
            <Button Name="addButton" Content="Send Add Text Command" Margin="5" />
        </StackPanel>
        <TextBox x:Name="beCleardeText" Height="80" Margin="5" Text="鸿雁长飞光不度,鱼龙潜跃水成文"/>
    </StackPanel>

后端 :

        private RoutedCommand m_clearCmd=new RoutedCommand("Clear",typeof(CommandTab)); //RoutedCommand与业务逻辑无关
        private RoutedCommand m_addCmd = new RoutedCommand("Add", typeof(CommandTab));
        
        public CommandTab()
        {
            InitializeComponent();
            InitCommand();
        }

        private void InitCommand()
        {
            clearButton.Command = m_clearCmd; //命令赋值给命令源
            m_clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt)); //指定快捷键
            clearButton.CommandTarget = beCleardeText; //指定命令目标

            //创建命令关联
            CommandBinding cb = new CommandBinding();
            cb.Command = m_clearCmd;
            cb.CanExecute += cb_CanExecute;
            cb.Executed += Cb_Executed;

            clearStackPanel.CommandBindings.Add(cb); //命令关联安置在外围控件,不然无法捕捉CanExecute、Executed等路由事件


            addButton.Command = m_addCmd;
            m_addCmd.InputGestures.Add(new KeyGesture(Key.A, ModifierKeys.Alt));
            addButton.CommandTarget = beCleardeText;
            CommandBinding addCb=new CommandBinding();
            addCb.Command = m_addCmd;
            addCb.CanExecute += AddCb_CanExecute;
            addCb.Executed += AddCb_Executed;
            clearStackPanel.CommandBindings.Add(addCb);
        }

        private void Cb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            beCleardeText.Clear();
            e.Handled = true;
        }

        private void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(beCleardeText.Text))
                e.CanExecute = false;
            else
                e.CanExecute = true;
            e.Handled = true;  //CanExecute激发频率较高,handled避免影响性能
        }

        private void AddCb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            beCleardeText.Text = "山高月小,水落石出";
            e.Handled = true;
        }

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

二、自定义Command 

首先定义一个接口,约束命令的作用目标。每个需要接受命令的组件都要实现这个接口,确保命令可以成功地执行。

    public interface IView
    {
        void Clear();

        void Fill();
    }

其次,创建自定义命令,实现 ICommand接口。业务逻辑被引入到Execute方法中

    /// <summary>
    /// 作用于 IView派生类的填充命令
    /// </summary> 
    public class FillCommand : ICommand
    {
        //命令可执行状态发生改变时被激发
        public event EventHandler? CanExecuteChanged;

        //用于判断命令是否可以执行
        public bool CanExecute(object? parameter)
        {
            throw new NotImplementedException();
        }

        public void Execute(object? parameter)
        {
            IView view =parameter as IView;
            if(view != null)
            {
                view.Fill();
            }
        }
    }

然后,创建自己的命令源 ,需要实现 ICommandSource 接口

    /// <summary>
    /// 创建命令源
    /// </summary>
    public class MyCommandSource : UserControl, ICommandSource
    {
        public ICommand Command {get; set;}

        public object CommandParameter {get; set;}

        public IInputElement CommandTarget {get; set;}

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

            //在命令目标上执行命令
            if(CommandTarget != null)
            {
                Command.Execute(CommandTarget);
            }
        }
    }

之后,创建命令目标,目标需实现 IView接口

界面:

<UserControl x:Class="WPF深入浅出.Controls.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:WPF深入浅出.Controls"
             mc:Ignorable="d" >
    <StackPanel>
        <TextBox Name="text1" Margin="5" MinWidth="100" MinHeight="50" FontSize="20"/>
        <TextBox Name="text2" Margin="5,0" MinWidth="100" MinHeight="50" FontSize="20"/>
    </StackPanel>
</UserControl>

后端:

    public partial class MiniView : UserControl,IView
    {
        public MiniView()
        {
            InitializeComponent();
        }

        public void Clear()
        {
            text1.Clear();
            text2.Clear();
        }

        public void Fill()
        {
            text1.Text = "樱桃樊素口";
            text2.Text = "杨柳小蛮腰";           
        }
    }

 最后,将命令、命令源和命令目标集成起来

 界面:

    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <controls:MiniView x:Name="miniView" Margin="5 50 5 40"/>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                <wpf深入浅出:MyCommandSource x:Name="ctrlFill">
                    <TextBlock Text="填充" FontSize="16" TextAlignment="Center" Background="LightGreen" Width="80" Margin="0 0 50 0"/>
                </wpf深入浅出:MyCommandSource>
                <wpf深入浅出:MyCommandSource x:Name="ctrlClear">
                    <TextBlock Text="清除" FontSize="16" TextAlignment="Center" Background="LightGreen" Width="80"/>
                </wpf深入浅出:MyCommandSource>
            </StackPanel>
        </StackPanel>
    </Grid>

 后端:

        private void InitCommand()
        {
            FillCommand fillCommand = new FillCommand();
            ctrlFill.Command = fillCommand;
            ctrlFill.CommandTarget = miniView;

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

todo:使用ICommand和 ICommandSource 的成员组成逻辑,通过Command的CanExecute方法返回值来影响命令源的状态 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值