C# winForm类似CAD命令的处理方法

仿CAD命令实现目标:在窗体中,有一可供用户输入命令的文本框te_Command,用户输入命令后按回车/空格,窗体可以执行相应的方法。

传统思路是在te_Command的KeyUp事件订阅器里使用switch(te_Command.Text){},但是这种方法当命令多了以后,代码的可读性和可扩展性都不是很好,改起来也比较麻烦。

解决思路:

1、创建一个自定义特性类,用于标识方法对应的命令和功能名称:

/// <summary>
    /// 命令处理方法特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class DcHandlerAttribute : Attribute
    {
        /// <summary>
        /// 对应的命令文本字符串数组
        /// </summary>
        public string[] CommandText { get; set; }
        /// <summary>
        /// 对应的功能名称
        /// </summary>
        public string FcName { get; set; }
        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="commandText">命令文本字符串数组</param>
        /// <param name="fcName">功能名称</param>
        public DcHandlerAttribute(string[] commandText, string fcName)
        {
            CommandText = commandText;
            FcName = fcName;
        }
    }
自定义命令处理方法特性

2、创建一个命令功能名称和委托的类,用于存储功能名称和其对应的方法的委托:

    /// <summary>
    /// 命令功能名称和处理方法委托类
    /// </summary>
    public class Cl_CommandHandler
    {
        /// <summary>
        /// 功能名称    
        /// </summary>
        public string FcName { get; set; }
        /// <summary>
        /// 处理方法的委托
        /// </summary>
        public Action Handler { get; set; }
        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="fcname">功能名称</param>
        /// <param name="handler">处理方法的委托</param>
        public Cl_CommandHandler(string fcname, Action handler)
        {
            FcName = fcname;
            Handler = handler;
        }
    }
命令功能名称和处理方法委托类

3、在窗体中设置一个字典

public Dictionary<string, Cl_CommandHandler> CommandHandlerDic;

4、创建上述字典,此方法在窗体的构造函数中调用。

        /// <summary>
        /// 使用反射技术,自动探测含有特定特性的方法,初始化命令、委托对应字典
        /// </summary>
        private void InitializeCommandHandler()
        {
            //初始化命令字典
            CommandHandlerDic = new Dictionary<string, Cl_CommandHandler>();
            //取得fm_Design类的所有私有动态方法
            foreach (var m in typeof([当前窗体类名]).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance))
            {
                //取得方法的特性
                var atts = m.GetCustomAttributes();
                if (atts.Count() > 0)
                {
                    foreach (var item in atts)
                    {
                        if (item is DcHandlerAttribute att)
                        {
                            //命令字符串数组
                            var ctext = att.CommandText;
                            //功能名称
                            var fcname = att.FcName;
                            //创建私有方法的Action委托
                            var a = Delegate.CreateDelegate(typeof(Action), this, m) as Action;
                            var dch = new Cl_CommandHandler(fcname, a);
                            //添加或修改命令、委托对应数组
                            for (int i = 0; i < ctext.Length; i++)
                            {
                                if (!CommandHandlerDic.ContainsKey(ctext[i]))
                                    CommandHandlerDic.Add(ctext[i], dch);
                                else
                                    CommandHandlerDic[ctext[i]] = dch;
                            }
                        }//包含命令处理特性时
                    }//遍历特性
                }//包含特性时
            }//遍历所有方法
        }
创建字典

5、te_Command的键抬起处理方法

        /// <summary>
        /// 命令栏KeyUp事件初始处理方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void te_Command_KeyUp(object sender, KeyEventArgs e)
        {
            //抬起回车键或空格键
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Space)
            {
                te_Command.Text = te_Command.Text.Trim().ToUpper();
                var commandText = te_Command.Text;
                if (string.IsNullOrEmpty(commandText)) return;
                if (CommandHandlerDic.ContainsKey(commandText))
                {
                    //执行委托
                    CommandHandlerDic[commandText].Handler();
                }
                te_Command.Text="";
            }
            //Esc键
            else if (e.KeyCode == Keys.Escape)
            {
                te_Command.Text = "";
            }
        }
命令栏KeyUp事件初始处理方法

 

 6、这样以后想增加某个命令时,只需要在方法前加上自定义特性即可:

        [DcHandler(new string[] { "ST", "START" }, "初始化")]
        private void Dch_Start()
        {
            //具体实现代码...
        }
        [DcHandler(new string[] { "BACK" }, "关闭")]
        private void Dch_Back()
        {
            //具体实现代码...
        }
        [DcHandler(new string[] { "?", "H", "HELP" }, "帮助")]
        private void Dch_Help()
        {
            //具体实现代码...
        }
        [DcHandler(new string[] { "EXIT", "QUIT" }, "退出")]
        private void Dch_Quit()
        {
            //具体实现代码...
        }
命令处理方法

 

构建窗体时,会自动检查含有自定义特性的方法,然后建立命令字符串-委托的字典。当用户在te_Command里输入命令后,程序会在字典里寻找对应的委托来执行。

当然还需要另外一个显示命令执行情况的文本框。

 

posted @ 2020-08-13 16:50  zeahon  阅读(707)  评论(4)    收藏  举报