zoukankan      html  css  js  c++  java
  • 命令者模式


       最近整一个WinForm界面,上面拖了100来个控件-有菜单、工具栏、命令按钮,做的时候设置这些控件的Enabled就够头大了,在不画界面操作流程图的情况下做起来就是一团乱麻。通过坚韧不拔的意志做完后,突然想起很多年前MS的IssueVision中似乎有个叫命令者模式的东东,于是就翻出并整理如下:

     命令者模式可以看作是命令模式的变形,主要用来解决UI上多个控件跟某个具体命令关联问题,一方面命令者将命令的Enabled状态变更转化成对应控件的Enabled状态变更,另一方面命令者提供对应控件点击事件的处理函数HandleUIEvent(将具体请求路由给内部引用Command处理)。

    从图中可见每个命令者对应一个具体的控件并关联一个命令,命令者订阅命令的EnableChangedEventHandler事件(命令可用状态改变),通过事件模型(这个可以看作C#的观察者模式实现)设置对应的控件的Enabled属性,一个命令实例可以关联多个命令者实例(的如菜单命令者、button按钮命令者)

    //==========命令的定义代码===============

    典型的命令模式代码,只不过接收者(Receiver)是Action委托,应此就省略了ICommand接口

    View Code
    public class Command 
    {
    // The EnableChanged event is raised when the IsEnabled value of the command
    // changes. This is handled in the Commander objects to set the Enabled property
    // of the managed controls.
    public delegate void EnableChangedEventHandler(object sender, Command.EnableChangedEventArgs e);
    public virtual event EnableChangedEventHandler EnableChanged;
    public delegate void Action();

    private Action m_action;
    private bool m_isEnabled = true;

    // The IsEnabled property is used to set/retrieve the enabled state of all UI
    // controls that the command manages
    public bool IsEnabled
    {
    get
    {
    return m_isEnabled;
    }

    set
    {
    if (m_isEnabled != value)
    {
    m_isEnabled = value;
    if (EnableChanged != null)
    {
    EnableChanged(this, new EnableChangedEventArgs(IsEnabled));
    }
    }
    }
    }

    public Command(Action action)
    {
    m_action = action;
    }

    // Invokes the method assigned to this command.
    public void Execute()
    {
    m_action();
    }

    // Arguments passed to the EnableChanged event.
    public class EnableChangedEventArgs : EventArgs
    {
    private bool m_isEnabled = false;

    public bool IsEnabled
    {
    get
    {
    return m_isEnabled;
    }
    }

    public EnableChangedEventArgs(bool isEnabled)
    {
    m_isEnabled = isEnabled;
    }
    }
    }

     //===================命令者实现==========================

    使用了抽象类(应该是模板模式),来避免重复代码

    View Code
        public abstract class Commander 
    {
    protected Command m_command;
    protected abstract void HandleEnableChangedEvent(object sender, Command.EnableChangedEventArgs e);

    protected Commander(Command command)
    {
    m_command = command;
    m_command.EnableChanged += new Command.EnableChangedEventHandler(this.HandleEnableChangedEvent);
    }
    }

    // MenuItemCommander class
    public class MenuItemCommander : Commander
    {
    private MenuItem m_item;

    protected MenuItemCommander(MenuItem item, Command command) : base(command)
    {
    m_item = item;
    m_item.Click += new EventHandler(this.HandleUIEvent);
    }

    protected override void HandleEnableChangedEvent(object sender, Command.EnableChangedEventArgs e)
    {
    m_item.Enabled = e.IsEnabled;
    }

    private void HandleUIEvent(object sender, EventArgs e)
    {
    m_command.Execute();
    }

    // Connect is a shared (static) method that performs the task of adapting a menu
    // item to a command. The commander exists only to wire up the two objects --
    // it is not used further
    public static void Connect(MenuItem item, Command command)
    {
    MenuItemCommander unused = new MenuItemCommander(item, command);
    }
    }

     注意上面的Connect方法,期unused看上去是一个方法变量,但是在MenuItemCommander的构造函数中将该实例的HandleUIEvent方法绑定到菜单项的Click事件上了,m_item.Click += new EventHandler(this.HandleUIEvent);因此unused对象不会被释放
    //===========MainForm(UI)===================

    View Code
            private void InitializeCommands() 
    {
    // Wire up menus and toolbar buttons
    //Command pattern: File | Send & Receive
    //一个命令对应两个命令者(两控件)
    m_sendReceiveCommand = new Command(new Command.Action(this.SendReceive_Action));
    MenuItemCommander.Connect(menuSendReceive, m_sendReceiveCommand);
    ToolBarButtonCommander.Connect(tlbSendReceive, m_sendReceiveCommand);

    // Toolbar | Work Offline
    m_workOfflineCommand = new Command(new Command.Action(this.WorkOffline_Action));
    ToolBarButtonCommander.Connect(tlbOffline, m_workOfflineCommand);

    // File | new
    m_newIssueCommand = new Command(new Command.Action(this.NewIssue_Action));
    MenuItemCommander.Connect(this.menuNew, m_newIssueCommand);
    ToolBarButtonCommander.Connect(this.tlbNewIssue, m_newIssueCommand);

    // File | Logout and Exit
    m_logoutExitCommand = new Command(new Command.Action(this.LogoutExit_Action));
    MenuItemCommander.Connect(this.mnuLogoutExit, m_logoutExitCommand);

    // File | Exit
    m_exitCommand = new Command(new Command.Action(this.Exit_Action));
    MenuItemCommander.Connect(this.menuExit, m_exitCommand);

    // Help | About
    m_aboutCommand = new Command(new Command.Action(this.About_Action));
    MenuItemCommander.Connect(this.menuAbout, m_aboutCommand);
    }

     命令接收者定义

    View Code
    #region Command Actions 

    private void SendReceive_Action()
    {
    this.Cursor = Cursors.WaitCursor;
    this.m_issueSubject.SendReceiveIssueData(SyncThread.MainThread);
    this.Cursor = Cursors.Default;
    }

    private void WorkOffline_Action()
    {
    UpdateOnlineStatus();
    }

    private void About_Action()
    {
    // Display the About dialog
    AboutForm form = new AboutForm();

    form.Visible = false;
    form.ShowDialog(this);
    }

    private void NewIssue_Action()
    {
    // Display the new Issue dialog
    IssueNewForm form = new IssueNewForm(this);
    form.Subject = m_issueSubject;
    form.Show();
    }

    private void LogoutExit_Action()
    {
    // Delete settings file and exit
    UserSettings.Delete();
    m_saveUserSettings = false;
    this.Close();
    }

    private void Exit_Action()
    {
    this.Close();
    }

    #endregion
  • 相关阅读:
    fetch的优点
    gitignore不起作用
    css动画和js动画区别
    工业家居气象空气环境质量监测仪记录数据甲醛PM2.5二氧化碳大气压温湿度
    摆脱淘宝、京东、拼多多内部引流消费规则,自建网站利用其完成支付
    语音朗读模块TTS文本变量实时转语音朗读科大讯飞XFS5152CE芯片AI
    PCB altium designer AD10 AD20 导出DWG CAD文件 过孔问题
    【Creator3】如何在3D场景中实现炫酷传送门,和简单的小地图功能,RenderTexture技术应用
    B站视频:【Creator3】好玩的编队代码 魔性排列停不下来 附源码及出处
    B站视频:《四图猜词》 Part3 | CocosCreator游戏开发教程
  • 原文地址:https://www.cnblogs.com/wdfrog/p/2435745.html
Copyright © 2011-2022 走看看