vineri, 19 februarie 2010

Command Pattern

Command Pattern with DevExpress BarItems controls

Command Pattern is like a controller between the objects that send the requests and object that perform the operations.

It can support:

• Sending requests to different receivers

• Queuing, logging, and rejecting requests

• Composing higher-level transactions from primitive operations

• Redo and Undo functionality


Actors in Command Paterns:


Client
Executes an Action.
ICommand
Interface for a Request posted on toolbar
Invoker
Asks the Command to carry out the Action
Command
A class that implements the Execute operation by invoking operations on the
Receiver
Action
The operation that needs to be performed
Receiver
Any class that can perform the required Action


Commands can be assembled into composite commands in the Command class.
New commands can be added without disturbing existing ones.





I the following example I will use Command Pattern to build toolbars (Bars)/context menus with DevExpress controls.

Let's consider a view that shows some statistics that could be a chart or a grid.
A chart could have its own functionality like: rotate, zoom, chart type (bar, pie, lines), markers, palette.
Also, a grid has its own functionality: show row indicators, footer, filtering row, palette.
There is also common functionality for grids&charts like: show alert, define stat, freeze view, switch to chart/grid.

A view is a container. That has a grid, a chart and a toolbar:




The actors in my example are:

Client
User who presses one of the bar item of the tooolbar of the view (do an Action).
ICommand
Interface for a Request posted on toolbar
Command
Holder of a request putted on the toolbar (An class that contains a pointers to methods that performs actions and a reference to the BarItem (BarButtonItem, BarCheckItem, BarSubItem))
Receiver
An object that can perform the actions (Grid, Char, Container).
Action
Palette selected, Zoom, Rotate, Show Indicator, ...


Because a Receiver (Chart, Grid, Container) could register multiple commands, I am not given a reference to a receiver, but one to a method from the receiver that can handle the execute action - A delegate.
In my sample Undo and Redo serve only as abstract placeholders.

    public interface ICommand
    {
        EventHandler Execute { get; }
        EventHandler Redo { get; }
        EventHandler Undo { get; }
    }

    public interface ICommand<T> : ICommand where T : BarItem
    {
        T BarItem { get; }

        ICommand<S> AddCommand<S>(string i_caption, string i_hint, int i_imageIndex, EventHandler i_Execute) where S : BarItem, new();

        ICommand<S> AddCommand<S>(string i_caption, int i_imageIndex, EventHandler i_Execute) where S : BarItem, new();
        ICommand<S> AddCommand<S>(string i_caption, string i_hint, int i_imageIndex, EventHandler i_Execute, bool i_beginGroup) where S : BarItem, new();
        ICommand<S> AddCommand<S>(ICommand<S> i_command) where S : BarItem, new();
        ICommand<S> AddCommand<S>(ICommand<S> i_command, bool i_beginGroup) where S : BarItem, new();
    }


In order to be able to add BarItems you need a BarManager, a StandaloneBarDockControl and a Bar or PopupMenu:

public class BarManagerEx : BarManager
    {
        private readonly BarDockControl barDockControlBottom;
        private readonly BarDockControl barDockControlLeft;
        private readonly BarDockControl barDockControlRight;
        private readonly BarDockControl barDockControlTop;
        private readonly IContainer m_container;

        public BarManagerEx(IContainer i_container, Control m_parentForm, ImageList i_imageList) : base(i_container)
        {
            m_container = i_container;
            BeginInit();

            barDockControlTop = new BarDockControl();
            barDockControlBottom = new BarDockControl();
            barDockControlLeft = new BarDockControl();
            barDockControlRight = new BarDockControl();


            DockControls.Add(barDockControlTop);
            DockControls.Add(barDockControlBottom);
            DockControls.Add(barDockControlLeft);
            DockControls.Add(barDockControlRight);

            m_parentForm.SuspendLayout();
            m_parentForm.Controls.Add(barDockControlLeft);
            m_parentForm.Controls.Add(barDockControlRight);
            m_parentForm.Controls.Add(barDockControlBottom);
            m_parentForm.Controls.Add(barDockControlTop);
            m_parentForm.ResumeLayout();

            AllowCustomization = false;
            AllowQuickCustomization = false;
            Form = m_parentForm;
            Images = i_imageList;
            MaxItemId = 112;

            EndInit();
        }

        public StandaloneBarDockEx AddStandaloneBarDock(Control i_parentControl)
        {
            StandaloneBarDockEx _barDock = StandaloneBarDockEx.Create(this, i_parentControl);
            return _barDock;
        }

        public PopupMenuEx AddPopup()
        {
            PopupMenuEx _popupMenu = PopupMenuEx.Create(this, m_container);
            return _popupMenu;
        }
    }


 public class StandaloneBarDockEx : StandaloneBarDockControl
    {
        private StandaloneBarDockEx() { }

        public static StandaloneBarDockEx Create(BarManager i_barManager, Control i_parent)
        {
            i_barManager.BeginInit();
            StandaloneBarDockEx _standaloneBarDockControl = new StandaloneBarDockEx();
            i_barManager.DockControls.Add(_standaloneBarDockControl);
            _standaloneBarDockControl.Appearance.BackColor = System.Drawing.Color.Transparent;
            _standaloneBarDockControl.Appearance.BackColor2 = System.Drawing.Color.Transparent;
            _standaloneBarDockControl.Appearance.BorderColor = System.Drawing.Color.Transparent;
            _standaloneBarDockControl.Appearance.Options.UseBackColor = true;
            _standaloneBarDockControl.Appearance.Options.UseBorderColor = true;
            _standaloneBarDockControl.AutoSizeInLayoutControl = false;
            _standaloneBarDockControl.Dock = System.Windows.Forms.DockStyle.Fill;
            _standaloneBarDockControl.Location = new System.Drawing.Point(0, 0);
            _standaloneBarDockControl.Size = new System.Drawing.Size(676, 27);
            i_parent.Controls.Add(_standaloneBarDockControl);
            i_barManager.EndInit();
            return _standaloneBarDockControl;
        }

        public BarEx AddBar(string i_caption, int i_dockCol, int i_dockRow)
        {
            BarEx _newBar = BarEx.Create(i_caption, Manager, this, i_dockCol, i_dockRow);
            return _newBar;
        }
    }

public class BarEx : Bar
    {
        private BarEx() { }

        internal static BarEx Create(string i_caption, BarManager i_barManager, StandaloneBarDockControl i_barDockParent, int i_dockCol, int i_dockRow)
        {
            BarEx i_bar = new BarEx();
            i_barManager.BeginInit();
            i_barManager.Bars.Add(i_bar);
            i_bar.Appearance.BackColor = System.Drawing.Color.Transparent;
            i_bar.Appearance.BackColor2 = System.Drawing.Color.Transparent;
            i_bar.Appearance.BorderColor = System.Drawing.Color.Transparent;
            i_bar.Appearance.Options.UseBackColor = true;
            i_bar.Appearance.Options.UseBorderColor = true;
            i_bar.BarName = i_caption;
            i_bar.CanDockStyle = BarCanDockStyle.Standalone;
            i_bar.DockCol = i_dockCol;
            i_bar.DockRow = i_dockRow;
            i_bar.DockStyle = BarDockStyle.Standalone;
            i_bar.FloatLocation = new System.Drawing.Point(200, 268);
            i_bar.OptionsBar.DrawDragBorder = false;
            i_bar.OptionsBar.RotateWhenVertical = false;
            i_bar.DockInfo.DockControl = new BarDockControl();
            i_bar.StandaloneBarDockControl = i_barDockParent;
            i_bar.Text = i_caption;
            i_barManager.EndInit();
            return i_bar;
        }

        public ICommand<T> AddCommand<T>(string i_caption, int i_imageIndex, EventHandler i_Execute) where T : BarItem, new()
        {
            return AddCommand<T>(i_caption, i_caption, i_imageIndex, i_Execute, false);
        }

        public ICommand<T> AddCommand<T>(string i_caption, int i_imageIndex, EventHandler i_Execute, bool i_beginGroup) where T : BarItem, new()
        {
            return AddCommand<T>(i_caption, i_caption, i_imageIndex, i_Execute, i_beginGroup);
        }

        public ICommand<T> AddCommand<T>(string i_caption, string i_hint, int i_imageIndex, EventHandler i_Execute, bool i_beginGroup) where T : BarItem, new()
        {
            ICommand<T> _cmd = new Command<T>(i_caption, i_imageIndex, i_Execute, Manager);
            _cmd.BarItem.Hint = i_hint;
            _cmd.BarItem.Description = i_hint;
            Manager.Items.Add(_cmd.BarItem);
            LinksPersistInfo.Add(new LinkPersistInfo(_cmd.BarItem, i_beginGroup));
            return _cmd;
        }

    }

public class Command<T> : ICommand<T> where T : BarItem, new()
    {
        private readonly T m_barItem;
        private readonly EventHandler m_Execute;
        private readonly BarManager m_barManager;
        internal Command(string i_caption, int i_imageIndex, EventHandler i_Execute, BarManager i_barManager)
        {
            m_barItem = new T();
            m_barManager = i_barManager;
            m_barManager.Items.Add(m_barItem);
            m_barItem.Caption = i_caption;
            m_barItem.Hint = i_caption;
            m_barItem.ImageIndex = i_imageIndex;

            m_barItem.PaintStyle = BarItemPaintStyle.CaptionInMenu;
            m_Execute = i_Execute;

            if (m_barItem is BarSubItem)
            {
                (m_barItem as BarSubItem).Popup += this.m_barSubItem_Popup;
            }
            else
            {
                if (m_barItem is BarButtonItem)
                {
                    (m_barItem as BarButtonItem).ButtonStyle = BarButtonStyle.Check;
                    (m_barItem as BarButtonItem).ItemClick += Command_ItemClick;
                }
                else
                {
                    if (m_barItem is BarCheckItem)
                    {
                        (m_barItem as BarCheckItem).CheckedChanged += Command_ItemClick;
                    }
                }
            }
        }

        public ICommand<S> AddCommand<S>(string i_caption, string i_hint, int i_imageIndex, EventHandler i_Execute) where S : BarItem, new()
        {
            return AddCommand<S>(i_caption, i_imageIndex, i_Execute);
        }

        public ICommand<S> AddCommand<S>(string i_caption, int i_imageIndex, EventHandler i_Execute) where S : BarItem, new()
        {
            return AddCommand<S>(i_caption, i_caption, i_imageIndex, i_Execute, false);
        }

        public ICommand<S> AddCommand<S>(string i_caption, string i_hint, int i_imageIndex, EventHandler i_Execute, bool i_beginGroup) where S : BarItem, new()
        {
            ICommand<S> _cmd = null;
            if (m_barItem is BarSubItem)
            {
                _cmd = new Command<S>(i_caption, i_imageIndex, i_Execute, m_barManager);
                m_barManager.Items.Add(_cmd.BarItem);
                (m_barItem as BarSubItem).LinksPersistInfo.Add(new LinkPersistInfo(_cmd.BarItem, i_beginGroup));
                return _cmd;
            }

            return _cmd;
        }

        void Command_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (Execute != null)
            {
                Execute(sender, e);
            }
        }

        public ICommand<S> AddCommand<S>(ICommand<S> i_command) where S : BarItem, new()
        {
            return AddCommand(i_command, false);
        }

        public ICommand<S> AddCommand<S>(ICommand<S> i_command, bool i_beginGroup) where S : BarItem, new()
        {
            if (m_barItem is BarSubItem)
            {
                LinkPersistInfo lpi = new LinkPersistInfo(i_command.BarItem);
                (m_barItem as BarSubItem).LinksPersistInfo.Add(lpi);
                lpi.BeginGroup = i_beginGroup;
            }
            return i_command;
        }

        private void m_barSubItem_Popup(object sender, EventArgs e)
        {
            if (Execute != null)
            {
                Execute(sender, e);
            }
        }

        #region ICommand<T> Members

        public T BarItem
        {
            get { return m_barItem; }
        }

        public EventHandler Execute
        {
            get { return m_Execute; }
        }

        public EventHandler Redo
        {
            get { throw new NotImplementedException(); }
        }

        public EventHandler Undo
        {
            get { throw new NotImplementedException(); }
        }
        #endregion
    }

}

Usage:



m_barManager = new BarManagerEx(components, this, m_imageList);
m_standaloneBarDockControlHome = m_barManager.AddStandaloneBarDock(m_container);

m_barGridSettings = m_standaloneBarDockControlHome.AddBar("Grid Settings", 0, 0);

            m_commandGridLookFeel =
                m_barGridSettings.AddCommand<BarSubItem>("Look && Feel", 54, m_barSubItemLookAndFeel_Popup);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("Flat", -1, m_barButtonItemGridStyle_ItemClick);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("Ultra Flat", -1, m_barButtonItemGridStyle_ItemClick);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("3D", -1, m_barButtonItemGridStyle_ItemClick);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("Office 2003", -1, m_barButtonItemGridStyle_ItemClick);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("Classic", "Classic", - 1, m_barButtonItemGridPalette_ItemClick, true);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("Brick", -1, m_barButtonItemGridPalette_ItemClick);
            m_commandGridLookFeel.AddCommand<BarButtonItem>("Desert", -1, m_barButtonItemGridPalette_ItemClick);

....

m_barChart = m_standaloneBarDockControlHome.AddBar("Chart Settings", 4, 0);
            _command = m_barChart.AddCommand<BarSubItem>("Palette Selector", 54, m_barSubItemPaletteSelector_Popup);
            m_barSubItemPaletteSelector = _command.BarItem;
            _command.BarItem.PaintStyle = BarItemPaintStyle.CaptionInMenu;
            _command.AddCommand<BarCheckItem>("Default", "Default Palette", 82, m_barCheckItemChartColor_ItemClick).BarItem.Tag = "Default";
            _command.AddCommand<BarCheckItem>("Schemes Colorful", "Schemes Colorful Palette", 81, m_barCheckItemChartColor_ItemClick).BarItem.Tag = "Schemes.Colorful";
            _command.AddCommand<BarCheckItem>("Nature Sky", "Nature Sky Palette", 86, m_barCheckItemChartColor_ItemClick).BarItem.Tag = "Nature.Sky";
            _command.AddCommand<BarCheckItem>("Earth Tones", "Earth Tones Palette", 83, m_barCheckItemChartColor_ItemClick).BarItem.Tag = "ChartFX6.EarthTones";
            _command.AddCommand<BarCheckItem>("Modern Business", "Modern Business Palette", 85, m_barCheckItemChartColor_ItemClick).BarItem.Tag = "ChartFX6.ModernBusiness";




Niciun comentariu:

Trimiteți un comentariu