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";