首页 > 学院 > 开发设计 > 正文

C#:WinForm之Command

2019-11-14 13:38:24
字体:
来源:转载
供稿:网友

  本文主要介绍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             else127             {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             else153             {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 代码

 

   补充:不好意思,忘记附上Demo示例,现补上,请前往 百度网盘 下载

 

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表