转载

C#:WinForm之Command

本文主要介绍WinForm项目中如何像WPF一样优雅的使用Command来实现业务操作。想必大家已经疲于双击控件生成事件处理方法来实现业务操作,如多控件(按钮、菜单、工具条、状态栏等命令控件)来做同一个动作,还要控制它们启用(Enabled)状态等等,使代码结构冗长且可读性差。下面具体介绍和实现WinForm中对Command的应用。

  1. 命令(Command)

    顾 名思义,定义一个命令,继承至System.Windows.Input.ICommand接口,实现 Execute(object) ,CanExecute(object)方法和 CanExecuteChanged事件。由 CanExecute 确定是否调用 Execute 执行该命令。

       1     /// <summary>  2     /// 定义一个执行的命令。  3     /// </summary>  4     public abstract class Command : ICommand  5     {  6         /// <summary>  7         /// The can executable  8         /// </summary>  9         private bool canExecutable = true; 10  11         /// <summary> 12         /// 当出现影响是否应执行该命令的更改时发生。 13         /// </summary> 14         public event EventHandler CanExecuteChanged; 15  16         /// <summary> 17         /// 定义用于确定此命令是否可以在其当前状态下执行的方法。 18         /// </summary> 19         /// <param name="parameter">此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 null。</param> 20         /// <returns>如果可以执行此命令,则为 true;否则为 false。</returns> 21         public abstract bool CanExecute(object parameter); 22  23         /// <summary> 24         /// 定义在调用此命令时调用的方法。 25         /// </summary> 26         /// <param name="parameter">此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 null。</param> 27         public abstract void Execute(object parameter); 28  29  30         /// <summary> 31         /// 提升命令状态更改。 32         /// </summary> 33         /// <param name="parameter">The parameter.</param> 34         internal protected void RaiseCommandState(object parameter) 35         { 36             var able = CanExecute(parameter); 37             if (able != canExecutable) 38             { 39                 canExecutable = able; 40                 OnCanExecuteChanged(EventArgs.Empty); 41             } 42         } 43  44         /// <summary> 45         /// 触发当命令状态更改事件。 46         /// </summary> 47         /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> 48         protected virtual void OnCanExecuteChanged(EventArgs e) 49         { 50             if (CanExecuteChanged != null) 51             { 52                 CanExecuteChanged(this, e); 53             } 54         } 55     }  Command 代码
  2. 命令参数(CommandParameter)

    提供给命令执行时的参数,该对象主要由参数源(Source)和参数源的属性(Parameter)构成。参数源可继承至System.ComponentModels.INotifyPropertyChanged接口,实现属性值更改通知。此 Parameter 必须为属性(也可以是静态属性)。

        1     /// <summary>   2     /// 表示命令参数。   3     /// </summary>   4     public sealed class CommandParameter   5     {   6         private readonly Type sourceType;   7         private readonly object source;   8         private readonly string propertyMember;   9   10         private readonly bool booleanOppose = false;  11         private Command command;  12   13         /// <summary>  14         /// 获取一个值,该值表示命令参数源。  15         /// </summary>  16         /// <value>The source.</value>  17         public object Source  18         {  19             get { return source; }  20         }  21   22         /// <summary>  23         /// 获取一个值,该值表示命令参数的类型若当前非静态类型绑定则为 Source 类型。  24         /// </summary>  25         /// <value>The type of the source.</value>  26         public Type SourceType  27         {  28             get  29             {  30                 return sourceType;  31             }  32         }  33   34         /// <summary>  35         /// 获取一个值,该值表示命令执行参数。  36         /// </summary>  37         /// <value>The parameter.</value>  38         public object Parameter { get { return ResolvePropertyValue(); } }  39   40         /// <summary>  41         /// 获取一个值,该值表示参数所属的命令。  42         /// </summary>  43         /// <value>The command.</value>  44         public Command Command  45         {  46             get  47             {  48                 return command;  49             }  50             internal set  51             {  52                 if (value != command)  53                 {  54                     command = value;  55                     command.RaiseCommandState(Parameter);  56                 }  57             }  58         }  59   60         /// <summary>  61         /// 初始化 RelateCommandParameter 新实例。  62         /// </summary>  63         /// <param name="source">绑定源。</param>  64         /// <param name="propertyMember">绑定成员(属性名称)。</param>  65         /// <param name="booleanOppose">若值为System.Boolean时,是否取反。</param>  66         public CommandParameter(object source, string propertyMember, bool booleanOppose = false)  67         {  68             this.source = source;  69             this.sourceType = source.GetType();  70             this.propertyMember = propertyMember;  71             this.booleanOppose = booleanOppose;  72             BindNotifyObject(source);  73         }  74   75         /// <summary>  76         /// 初始化 RelateCommandParameter 新实例。  77         /// </summary>  78         /// <param name="source">绑定源。</param>  79         /// <param name="propertyMember">绑定成员(属性名称)。</param>  80         /// <param name="booleanOppose">若值为System.Boolean时,是否取反。</param>  81         public CommandParameter(object source, Expression<Func<string>> propertyMember, bool booleanOppose = false)  82             : this(source, ResolvePropertyName(propertyMember), booleanOppose)  83         {  84   85         }  86   87         /// <summary>  88         /// 初始化一个可指定静态成员的 RelateCommandParameter 新实例。  89         /// </summary>  90         /// <param name="staticSourceType">静态类类型。</param>  91         /// <param name="propertyMember">绑定成员(属性名称)。</param>  92         /// <param name="booleanOppose">若值为System.Boolean时,是否取反。</param>  93         public CommandParameter(Type staticSourceType, string propertyMember, bool booleanOppose = false)  94         {  95             this.sourceType = staticSourceType;  96             this.propertyMember = propertyMember;  97             this.booleanOppose = booleanOppose;  98         }  99  100         private void BindNotifyObject(object source) 101         { 102             if (typeof(INotifyPropertyChanged).IsAssignableFrom(source.GetType())) 103             { 104                 ((INotifyPropertyChanged)source).PropertyChanged += SourcePropertyChanged; 105             } 106         } 107  108         private void SourcePropertyChanged(object sender, PropertyChangedEventArgs e) 109         { 110             if (e.PropertyName == propertyMember) 111             { 112                 if (Command != null) 113                 { 114                     Command.RaiseCommandState(Parameter); 115                 } 116             } 117         } 118  119         private object ResolvePropertyValue() 120         { 121             var flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic; 122             if (source == null) 123             { 124                 flags |= System.Reflection.BindingFlags.Static; 125             } 126             else 127             { 128                 flags |= System.Reflection.BindingFlags.Instance; 129             } 130  131             var pro = sourceType.GetProperty(propertyMember, flags); 132             if (pro == null) 133             { 134                 throw new MemberAccessException(string.Format("Not found {2} member /"{0}/" in /"{1}/"", propertyMember, sourceType, source == null ? "static" : "instance")); 135             } 136             if (Type.GetTypeCode(pro.PropertyType) == TypeCode.Boolean) 137             { 138                 if (booleanOppose) 139                 { 140                     return !((Boolean)pro.GetValue(source)); 141                 } 142             } 143             return pro.GetValue(source); 144         } 145  146         private static string ResolvePropertyName(Expression<Func<string>> propertyMember) 147         { 148             if (propertyMember != null) 149             { 150                 return ((MemberExpression)propertyMember.Body).Member.Name; 151             } 152             else 153             { 154                 throw new ArgumentNullException("propertyMember"); 155             } 156         } 157     }  CommandParameter 代码
  3. 命令绑定(CommandBinding)

    命令和命令参数组合构建成一个绑定对象。

       1     /// <summary>  2     /// 定义命令绑定对象。  3     /// </summary>  4     public sealed class CommandBinding  5     {  6         /// <summary>  7         /// 获取一个值,该值表示命令绑定的对象。  8         /// </summary>  9         /// <value>The command.</value> 10         public Command Command { get; private set; } 11  12         /// <summary> 13         /// 获取一个值,该值表示命令执行参数。 14         /// </summary> 15         /// <value>The command parameter.</value> 16         public CommandParameter CommandParameter { get; private set; } 17  18         /// <summary> 19         /// 初始化 <see cref="CommandBinding"/> 新实例。 20         /// </summary> 21         /// <param name="command">要绑定的命令。</param> 22         public CommandBinding(Command command) 23             : this(command, null) 24         { 25  26         } 27  28         /// <summary> 29         /// 初始化 <see cref="CommandBinding"/> 新实例。 30         /// </summary> 31         /// <param name="command">要绑定的命令。</param> 32         /// <param name="commandParameter">要绑定的命令参数。</param> 33         public CommandBinding(Command command, CommandParameter commandParameter) 34         { 35             this.Command = command; 36             this.CommandParameter = commandParameter; 37             if (this.CommandParameter != null) 38             { 39                 this.CommandParameter.Command = this.Command; 40             } 41         } 42  43         /// <summary> 44         /// 初始化 <see cref="CommandBinding"/> 新实例。 45         /// </summary> 46         /// <param name="command">要绑定的命令。</param> 47         /// <param name="source">要绑定的命令参数的实例。</param> 48         /// <param name="propertyMember">要绑定的命令参数的属性名称。</param> 49         /// <param name="booleanOppose">若值为System.Boolean值时,是否取反向值。</param> 50         public CommandBinding(Command command, object source, string propertyMember, bool booleanOppose = false) 51             : this(command, CreateCommandParameter(source, propertyMember, booleanOppose)) 52         { 53  54         } 55  56         /// <summary> 57         /// 初始化 <see cref="CommandBinding"/> 新实例。 58         /// </summary> 59         /// <param name="command">要绑定的命令。</param> 60         /// <param name="staticSourceType">静态类类型。</param> 61         /// <param name="propertyMember">绑定成员(属性名称)。</param> 62         /// <param name="booleanOppose">若值为System.Boolean时,是否取反。</param> 63         public CommandBinding(Command command, Type staticSourceType, string propertyMember, bool booleanOppose = false) 64             : this(command, new CommandParameter(staticSourceType, propertyMember, booleanOppose)) 65         { 66         } 67  68         private static CommandParameter CreateCommandParameter(object source, string propertyMember, bool booleanOppose = false) 69         { 70             return new CommandParameter(source, propertyMember, booleanOppose); 71         }  72     }  CommandBinding 代码
  4. 命令目标(CommandTarget)

    此为最终执行命令的目标,构建此对象实例时指定一个绑定(CommandBinding),监视WinForm命令控件(如 Control 、ToolStripItem)等包含 Click 事件和 Enabled 属性的对象。

        1     /// <summary>   2     /// 表示命令绑定的执行目标。   3     /// </summary>   4     public sealed class CommandTarget : IDisposable   5     {   6         private readonly object target;   7         private bool disposed = false;   8    9         /// <summary>  10         /// 获取一个值,该值表示目标是否已释放。  11         /// </summary>  12         /// <value><c>true</c> if disposed; otherwise, <c>false</c>.</value>  13         public bool Disposed { get { return disposed; } }  14   15         /// <summary>  16         /// 获取一个值,该值表示目标的命令绑定源。  17         /// </summary>  18         /// <value>The command binding.</value>  19         public CommandBinding CommandBinding { get; private set; }  20   21         /// <summary>  22         /// 初始化 CommandTarget 新实例。  23         /// </summary>   24         /// <param name="binding">命令绑定源。</param>  25         private CommandTarget(CommandBinding binding)  26         {  27             CommandBinding = binding;  28             CommandBinding.Command.CanExecuteChanged += CommandStateChanged;  29         }  30   31   32         /// <summary>  33         /// 初始化 CommandTarget 新实例。  34         /// </summary>  35         /// <param name="control">绑定目标。</param>  36         /// <param name="commandBinding">命令绑定源。</param>  37         public CommandTarget(Control control, CommandBinding commandBinding)  38             : this(commandBinding)  39         {  40             target = control;  41             control.Click += OnClick;  42             var parameter = GetParameterValue();  43             control.Enabled = commandBinding.Command.CanExecute(parameter);  44         }  45   46         /// <summary>  47         /// 初始化 CommandTarget 新实例。  48         /// </summary>  49         /// <param name="item">绑定目标。</param>  50         /// <param name="commandBinding">命令绑定源。</param>  51         public CommandTarget(ToolStripItem item, CommandBinding commandBinding)  52             : this(commandBinding)  53         {  54             target = item;  55             item.Click += OnClick;  56             var parameter = GetParameterValue();  57             item.Enabled = commandBinding.Command.CanExecute(parameter);  58         }  59   60   61         /// <summary>  62         /// Handles the <see cref="E:Click" /> event.  63         /// </summary>  64         /// <param name="sender">The sender.</param>  65         /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>  66         private void OnClick(object sender, EventArgs e)  67         {  68             object parameter = null;  69             if (CommandBinding.CommandParameter != null)  70             {  71                 parameter = CommandBinding.CommandParameter.Parameter;  72             }  73             var command = CommandBinding.Command;  74             if (command.CanExecute(parameter))  75             {  76                 command.Execute(parameter);  77             }  78         }  79         /// <summary>  80         /// Commands the state changed.  81         /// </summary>  82         /// <param name="sender">The sender.</param>  83         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>  84         private void CommandStateChanged(object sender, EventArgs e)  85         {  86             var property = target.GetType().GetProperty("Enabled");  87             if (property != null)  88             {  89                 var parameter = GetParameterValue();  90                 var enable = CommandBinding.Command.CanExecute(parameter);  91                 property.SetValue(target, enable);  92             }  93         }  94   95         private object GetParameterValue()  96         {  97             if (CommandBinding.CommandParameter == null)  98             {  99                 return null; 100             } 101             return CommandBinding.CommandParameter.Parameter; 102         } 103  104         /// <summary> 105         /// 执行与释放或重置非托管资源相关的应用程序定义的任务。 106         /// </summary> 107         public void Dispose() 108         { 109             if (disposed) 110             { 111                 return; 112             } 113             disposed = true; 114             CommandBindingManager.Unregister(this); 115             CommandBinding.Command.CanExecuteChanged -= CommandStateChanged; 116             if (target is Control) 117             { 118                 ((Control)target).Click -= OnClick; 119             } 120             if (target is ToolStripItem) 121             { 122                 ((Control)target).Click -= OnClick; 123             } 124         }  125     }  CommandTarget 代码
  5. 命令绑定管理器(CommandBindingManager)

    命令绑定管理器提供命令绑定(CommandBinding)与命令控件(WinForm控件)注册与反注册功能。

        1     /// <summary>   2     /// 表示命令注册管理器。   3     /// </summary>   4     public static class CommandBindingManager   5     {   6         private static readonly List<CommandTarget> targets = new List<CommandTarget>();   7    8         /// <summary>   9         /// 注册命令道指定的命令控件。  10         /// </summary>  11         /// <param name="control">绑定目标。</param>  12         /// <param name="commandBinding">命令绑定源。</param>  13         /// <returns>返回一个命令目标实例。</returns>  14         public static CommandTarget Register(Control control, CommandBinding commandBinding)  15         {  16             var target = new CommandTarget(control, commandBinding);  17             targets.Add(target);  18             return target;  19         }  20   21         /// <summary>  22         /// 注册命令道指定的命令控件。  23         /// </summary>  24         /// <param name="stripItem">绑定目标。</param>  25         /// <param name="commandBinding">命令绑定源。</param>  26         /// <returns>返回一个命令目标实例。</returns>  27         public static CommandTarget Register(ToolStripItem stripItem, CommandBinding commandBinding)  28         {  29             var target = new CommandTarget(stripItem, commandBinding);  30             targets.Add(target);  31             return target;  32         }  33   34         /// <summary>  35         /// 注册命令道指定的命令控件。  36         /// </summary>  37         /// <param name="control">绑定目标。</param>  38         /// <param name="command">绑定命令。</param>  39         /// <returns>返回一个命令目标实例。</returns>  40         public static CommandTarget Register(Control control, Command command)  41         {  42             return Register(control, new CommandBinding(command));  43         }  44         /// <summary>  45         /// 注册命令道指定的命令控件。  46         /// </summary>  47         /// <param name="stripItem">绑定目标。</param>  48         /// <param name="command">绑定命令。</param>  49         /// <returns>返回一个命令目标实例。</returns>  50         public static CommandTarget Register(ToolStripItem stripItem, Command command)  51         {  52             return Register(stripItem, new CommandBinding(command));  53         }  54   55         /// <summary>  56         /// 注册命令道指定的命令控件。  57         /// </summary>  58         /// <param name="control">绑定目标。</param>  59         /// <param name="command">绑定命令。</param>  60         /// <param name="source">构造命令参数的源。</param>  61         /// <param name="propertyName">构造命令参数的名称。</param>  62         /// <param name="booleanOppose">若值为System.Boolean值时,是否取反向值。</param>  63         /// <returns>返回一个命令目标实例。</returns>  64         public static CommandTarget Register(Control control, Command command, object source, string propertyName, bool booleanOppose = false)  65         {  66             var commandBinding = new CommandBinding(command, source, propertyName, booleanOppose);  67             return Register(control, commandBinding);  68         }  69   70         /// <summary>  71         /// 注册命令道指定的命令控件。  72         /// </summary>  73         /// <param name="stripItem">绑定目标。</param>  74         /// <param name="command">绑定命令。</param>  75         /// <param name="source">构造命令参数的源。</param>  76         /// <param name="propertyName">构造命令参数的名称。</param>  77         /// <param name="booleanOppose">若值为System.Boolean值时,是否取反向值。</param>  78         /// <returns>返回一个命令目标实例。</returns>  79         public static CommandTarget Register(ToolStripItem stripItem, Command command, object source, string propertyName, bool booleanOppose = false)  80         {  81             var commandBinding = new CommandBinding(command, source, propertyName, booleanOppose);  82             return Register(stripItem, commandBinding);  83         }  84   85         /// <summary>  86         /// 注册命令道指定的命令控件。  87         /// </summary>  88         /// <param name="control">绑定目标。</param>  89         /// <param name="command">绑定命令。</param>  90         /// <param name="staticSourceType">静态类类型。</param>  91         /// <param name="propertyName">构造命令参数的名称。</param>  92         /// <param name="booleanOppose">若值为System.Boolean值时,是否取反向值。</param>  93         /// <returns>返回一个命令目标实例。</returns>  94         public static CommandTarget Register(Control control, Command command, Type staticSourceType, string propertyName, bool booleanOppose = false)  95         {  96             var commandBinding = new CommandBinding(command, staticSourceType, propertyName, booleanOppose);  97             return Register(control, commandBinding);  98         }  99         /// <summary> 100         /// 注册命令道指定的命令控件。 101         /// </summary> 102         /// <param name="stripItem">绑定目标。</param> 103         /// <param name="command">绑定命令。</param> 104         /// <param name="staticSourceType">静态类类型。</param> 105         /// <param name="propertyName">构造命令参数的名称。</param> 106         /// <param name="booleanOppose">若值为System.Boolean值时,是否取反向值。</param> 107         /// <returns>返回一个命令目标实例。</returns> 108         public static CommandTarget Register(ToolStripItem stripItem, Command command, Type staticSourceType, string propertyName, bool booleanOppose = false) 109         { 110             var commandBinding = new CommandBinding(command, staticSourceType, propertyName, booleanOppose); 111             return Register(stripItem, commandBinding); 112         } 113           114         /// <summary> 115         /// 反注册命令。 116         /// </summary> 117         /// <param name="target">注销的命令目标。</param> 118         public static void Unregister(CommandTarget target) 119         { 120             if (target == null) 121             { 122                 return; 123             } 124             if (targets.Contains(target)) 125             { 126                 targets.Remove(target); 127                 target.Dispose(); 128             } 129         } 130     }  CommandBindingManager 代码

最后附上委托命令(DegelateCommand)的实现。

   1     /// <summary>  2     /// 表示一个可被执行委托的方法的命令。  3     /// </summary>  4     public sealed class DelegateCommand : Command  5     {  6         private Action<object> execute;  7         private Func<object, bool> canExecute;  8         /// <summary>  9         /// 初始化 <see cref="DelegateCommand"/> 新实例。 10         /// </summary> 11         /// <param name="execute">当命令被调用时,指定的方法。</param> 12         /// <param name="canExecute">当命令被确定是否能执行时,执行的方法。</param> 13         public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null) 14         { 15             this.execute = execute; 16             this.canExecute = canExecute; 17         } 18         /// <summary> 19         /// 定义用于确定此命令是否可以在其当前状态下执行的方法。 20         /// </summary> 21         /// <param name="parameter">此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 null。</param> 22         /// <returns>如果可以执行此命令,则为 true;否则为 false。</returns> 23         public override bool CanExecute(object parameter) 24         { 25             if (canExecute == null) 26             { 27                 return true; 28             } 29             return canExecute(parameter); 30         } 31  32         /// <summary> 33         /// 定义在调用此命令时调用的方法。 34         /// </summary> 35         /// <param name="parameter">此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 null。</param> 36         public override void Execute(object parameter) 37         { 38             if (CanExecute(parameter)) 39             { 40                 execute(parameter); 41             } 42         } 43     }   DelegateCommand 代码

本文如有纰漏,欢迎大家批评指正!                                   

正文到此结束
Loading...