WPF 命令(RoutedCommand自定义命令,实现 ICommand 接口自定义命令)。推荐使用实现 ICommand 接口自定义命令

强烈推荐阅读 http://www.cnblogs.com/Clingingboy/archive/2010/12/26/1917188.html

一、命令基本元素及关系

      我们已经知道WPF里已经有了路由事件,可以发布及传播一些消息,那为什么还需要命令呢?这是因为事件指负责发送消息,对消息如何处理则不管,而命令是有约束力,每个接收者对命令执行统一的行为,比如菜单上的保存,工具栏上的保存都必须是执行同样的保存。

 

在WPF中,命令(Commanding)被分割成了四个部分,分别是ICommand,ICommandSource,CommandTarget和CommandBinding。下面我们来分别探讨这四个部分。

   命令(Command):实现了ICommand接口的类,经常使用的有RoutedCommand类

           (private RoutedCommand clearCmd = newRoutedCommand("序列化的声明名称", typeof(所有者类型));)

   命令源:是命令的发送者,是实现了ICommandSource接口的类,大部分界面的控件都实现了这个接口,Button, MenuItem 等等。

                       (为按钮设置调用的命令 如:按钮.Command=)

   命令目标:命令的接收者,命令目标是视线了IInputElement接口的类。

                       (设置引发指定命令的元素 如:按钮.CommandTarget= )

   命令关联:负责一些逻辑与命令关联起来,比如判断命令是否可以执行,以及执行完毕后做一些处理。

                    1、CommandBinding  :将RoutedCommand 绑定到事件处理程序。

                            (

           //CommandBinding 将命令绑定到事件处理程序

                    CommandBinding cb = new CommandBinding();

            //命令

                   cb.Command = 命令对象;

            //事件处理程序

      cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);

      cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);

                             )

                    2、把命令关联安置在外围控件上(将命令CommandBinding添加到命令集合CommandBindings 中)

                            布局控件.CommandBindings.Add(CommandBinding对象);

四个命令元素之间的关系

 

实例一:RoutedCommand自定义命令:

                与业务逻辑无关的命令,使用 RoutedCommand,业务逻辑要依靠外围的CommandBinding来实现。这样一来,如果对CommandBinding管理不善就可能造成代码混乱无章,毕竟一个CommandBinding要牵扯到谁是它的宿主以及它的两的事件处理器。

 

 

使用 Button 来发送这个命令,当命令送达到 TextBox 时,TextBox被清空(如果TextBox没有文字,则命令不可以被发送)

效果:

 

代码:

 

    <StackPanel x:Name="stackpanel">
        <Button x:Name="button1" Content="发送命令" Margin="5"/>
        <TextBox x:Name="textboxA" Margin="5,0" Height="100"/>
    </StackPanel>

注意:

RoutedCommand 只负责跑腿,并不对命名目标做任何操作

CommandBinding 对命名目标做操作

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpfApplication
{
    /// <summary>
    /// Window9.xaml 的交互逻辑
    /// </summary>
    public partial class Window9 : Window
    {
        public Window9()
        {
            InitializeComponent();
            InitializeCommand();
        }

        //第一步:声明并定义命令(命令名称是Clear 所有者类型是Window9)
        //(RoutedCommand 只负责跑腿,并不对命名目标做任何操作)
        private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(Window9));

        private void InitializeCommand()
        {
            //第二步:把命令赋值给命令源(发送者),并指定快捷建
            this.button1.Command = this.clearCmd;
            this.clearCmd.InputGestures.Add(new KeyGesture(Key.C,ModifierKeys.Alt));

            //第三步:指定命令的目标
            this.button1.CommandTarget = this.textboxA;

            //第四步:创建命令关联(CommandBinding 对命名目标做操作)
            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);
        }

        //当探测命名是否可以执行时,此方法被调用
        public void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(this.textboxA.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
            //避免继续向上传而降低程序性能
            e.Handled = true;
        }

        //命令送达目标后,此方法被调用
        public void cb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.textboxA.Clear();
            //避免继续向上传而降低程序性能
            e.Handled = true;
        }

    }
}

推荐阅读:========================================================================================

    public partial class Window13 : Window
    {
        //第1步:定义路由命令
        private RoutedCommand clearCmd = new RoutedCommand();
        public Window13()
        {
            InitializeComponent();

            //第2步:为按钮指定【命令】
            this.button1.Command = clearCmd;

            //第3步:为按钮指定【命令目标】
            this.button1.CommandTarget = this.textboxA;

            //第4步:将路由命令绑定到事件处理程序
            var cb = new CommandBinding(clearCmd, ClearExcute, ClearCanExcute);

            //第5步:将路由命令绑定添加到命令集合中
            this.CommandBindings.Add(cb);

        }
        /// <summary>
        /// 可以执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearCanExcute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(this.textboxA.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
            //避免继续向上传而降低程序性能
            e.Handled = true;
        }
        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearExcute(object sender, ExecutedRoutedEventArgs e)
        {
            this.textboxA.Clear();
            //避免继续向上传而降低程序性能
            e.Handled = true;
        }
    }

实例二:WPF命令库,比如:复制,粘贴。。。

 

命令库包括:
    ApplicationCommands
   ComponentCommands
   NavigationCommands
   MediaCommands
   EditingCommands
它们都是静态类

推荐文章:桂素伟 WPF中的命令 http://axzxs.blog.51cto.com/730810/525418

 

 

 

实例三:命令中的参数传递(同个命令区分,需要参数)

 

代码:

<Window x:Class="WpfApplication.Window10"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window10" Height="300" Width="300">
    <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"/>
        <!--两个按钮都使用了New命令,使用Teacher,Student字符串作为参数-->
        <Button Content="新老师" Command="New" CommandParameter="Teacher" Grid.Row="2"/>
        <Button Content="新学生" Command="New" CommandParameter="Student" Grid.Row="4"/>
        <ListBox x:Name="listboxnewItem" Grid.Row="6"/>
    </Grid>
    <Window.CommandBindings>
        <CommandBinding Command="New" CanExecute="New_CanExecute" Executed="New_Executed"/>
    </Window.CommandBindings>

</Window>

 

 

        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.listboxnewItem.Items.Add(string.Format("新老师:{0}",name));
            }
            if (e.Parameter.ToString() == "Student")
            {
                this.listboxnewItem.Items.Add(string.Format("新学生:{0}", name));
            }
        }


实例四:命令与Binding结合(Command 属性调用多个命令)

 

<Button x:Name="dynamicCmdBtn" Command="{Binding Path=ppp,Source=sss}" Content="动态命令"/>

 

二、近观命令

1、ICommand接口与RoutedCommand

 

2、自定义命令(实现 ICommand 接口) (推荐)

      命令:实现 ICommand 接口开始,定义自己的命令并且把某些业务逻辑包含到命令中,这才是真正意义上的自定义命令。

     命令源: 实现 ICommandSource接口

     命令目标:

 

 

第一步:定义接口 IView.cs,并且需要接受命令的控件都要实现这个接口,这样就确保了命令可以成功对它执行操作。

 

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

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


第二步:创建命令 。ClearCommand.cs

 

 

    //命令
    //实现ICommand接口,并继承了CanExecuteChanged事件,CanExecute方法和Execute方法
    public class ClearCommand:ICommand
    {
        //当命令可执行状态发生改变时,应当被激活
        public event EventHandler CanExecuteChanged;

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

        public void Execute(object parameter)
        {
            //执行命令,带与业务相关的Clear逻辑
            IView view = parameter as IView;
            if (view != null)
            {
                view.Clear();
            }

        }
    }

                      执行用户控件MiniView的Clear()方法

 

 

 

第三步:命令源(调用命令的对象 如:按钮) MyCommandSource.cs

 

 

    //命令源
    public class MyCommandSource:UserControl1,ICommandSource
    {

        //继承 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.CommandTarget != null)
            {
                this.Command.Execute(CommandTarget);
            }
        }
    }

 

CommandTarget  命令目标 如:miniView

 

Command.Execute 点击鼠标左键,执行ClearCommand.cs中的Execute方法

 

第四步:命令目标

 

效果图:

用户控件:

 

<UserControl x:Class="WpfApplication.MiniView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="114" Width="200">
    <Border CornerRadius="5" BorderBrush="LawnGreen" BorderThickness="2">
        <StackPanel>
          <TextBox x:Name="textbox1" Margin="5"/>
          <TextBox x:Name="textbox2" Margin="5,0"/>
          <TextBox x:Name="textbox3" Margin="5"/>
          <TextBox x:Name="textbox4" Margin="5,0"/>
        </StackPanel>
    </Border>
</UserControl>

 

    /// <summary>
    /// 命令目标
    /// </summary>
    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();
        }
    }


第五步:将命令、命令源、命令目标集成起来

 

效果图:

 

代码:

 

<Window x:Class="WpfApplication.Window11"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication"
        Title="Window11" Height="300" Width="300">
    <StackPanel>
        <local:MyCommandSource x:Name="ctrlClear" Margin="10">
            <TextBlock Text="清除" FontSize="16" TextAlignment="Center" Background="LightBlue" Width="80"/>
        </local:MyCommandSource>
        <local:MiniView x:Name="miniView"/>
    </StackPanel>
</Window>

 

        public Window11()
        {
            InitializeComponent();

            //声明命令
            ClearCommand clearCommand = new ClearCommand();
            //命令源命令
            this.ctrlClear.Command = clearCommand;
            //命令源目标
            this.ctrlClear.CommandTarget = this.miniView;

            
        }

 

<span style="color:#ff0000">//注意:正规方法,应该把命令声明在静态全局的地方,供所有对象使用。</span>

 

 

 

实例:MVVM为按钮添加事件

 

DelegateCommand.cs

 

    public class DelegateCommand : ICommand
    {
        public Action<object> ExecuteCommand = null;
        public Func<object, bool> CanExecuteCommand = null;

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            if (CanExecuteCommand != null)
            {
                return this.CanExecuteCommand(parameter);
            }
            else
            {
                return true;
            }
        }
        public void Execute(object parameter)
        {
            if (this.ExecuteCommand != null) this.ExecuteCommand(parameter);
        }
        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
        }

    }


ViewModel.cs

 

 

 

 

    public class ViewModel
    {
        public DelegateCommand BuildCommand { get; set; }
        public ViewModel()
        {
            BuildCommand = new DelegateCommand();
            BuildCommand.ExecuteCommand = new Action<object>(Build);
        }
        private void Build(object obj)
        {
            MessageBox.Show(obj.ToString());
        }
    }

 

 

 

 

 

View.xaml

DataContext = new ViewModel();

        <Button Content="生 成" Height="50"  Width="100" 
                Command="{Binding BuildCommand}"
                CommandParameter="1"/>

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tiz198183

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值