Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Command Switchboard for Windows Forms

4.83/5 (16 votes)
12 Jul 2007CPOL8 min read 1   1.4K  
Switchboard component for user interface commands with design time support

Screenshot - DesignForm.png

Screenshot - ClassOverview.png

Introduction

This article describes a component for routing menu and toolbar item events through a centralized switchboard for easier execution and update. Windows Forms design-time support is also an important part of the software.

Background

I have always found the command update an execution architecture in MFC that is very easy to use. Despite all the good parts of Windows Forms, it is still missing this architecture: an easily isolated mechanism for updating menus and toolbars based on application state. I also wanted to research design-time support in Windows Forms, to see what is possible. So, I wrote this switchboard to provide a similar functionality in Windows Forms.

Description

An application command represents an action that you want to execute in your application. It can be triggered by a UI item, which can be a menu item, toolbar item or come directly from code. Your application should only handle application command updates and executions, not connect directly to UI items. Changes to a UI item is reflected in the application command and other associated UI items.

An application command can be executed by a UI item. Normally, this is a menu or toolbar item click. However, it can also be a selection change in a combo box or text that is changed in an edit box. Any event in a UI item can be used to execute a command. There can be one global execute handler and/or a specific execute handler for each application command. These commands can also be executed directly from code.

An application command sometimes has to be updated. The update normally involves enable/disable, check/uncheck or show/hide. The update can also be to select an element in a combo box or to change text in an edit box. There can be one global update handler and/or a specific update handler for each application command. The update can be activated for the application command or for each UI item. UI items should be updated when a context menu is shown. By adding the context menu to the context menu collection, all UI items in the context menu are updated when the menu is shown.

UISwitchboard uses an adapter pattern for supporting different types of menu and toolbar implementations. The adapter implements an interface defined by UISwitchboard. NET 2.0 Toolstrip menus and toolbars, as well as NET 1.x menus and toolbars, are supported by an adapter for each type. It is easy to write another adapter for third party menu and toolbar packages.

Using the Code

Adding Components to Toolbox

To use the Switchboard component, you have to add the component to the Visual Studio Toolbox by selecting the "Choose Items..." menu item in the toolbox context menu. In the ".NET Framework Components" tab, select the "Browse" button and browse for the UISwitchboard.dll assembly. Two new components, ToolStripUISwitcboard and MenuToolBarUISwitchboard, should now appear in the toolbox under the "Menus & Toolbars" group.

Adding Components to Form

You can now add the component to a Windows Form. Simply drag the component from the toolbox and drop the component on the surface of the form. The component is now added to the form and is visible below the form with all the other components you have added. You can now change the name and other properties on the component. A reference to the UISwitchboard assembly is added to the project by this action.

Screenshot - ComponentInForm.png

Figure 1: Component in form

Creating Application Commands

The next step is to define all application commands. These commands should be a logical set of commands that you will execute in the application. You can use either the smart tag menu on the component or the component properties to open the "Application Command Collection Editor." This editor is used to add, delete or edit an application command.

Screenshot - EditApplicationCommands.png

Figure 2: Editing application commands

You can also create application commands directly from your code by using the properties and methods on the UISwitchboard classes.

Associating UI Items with a Command

Application commands are triggered by UI items. Items have to be associated with a command to be able to trigger execution of the command. This association can be edited from the application command properties by opening the "UIItems" collection. This will open the "UIItem Associations Editor." This editor shows all available items and which items are associated with the current command. You can now add or remove associations between items and the current command.

Screenshot - EditUIItemAssociations.png

Figure 3: Edit UI item associations

You can also edit associations by selecting a UI item and using the "ApplicationCommand on xx" property for the item. Select the application command you want to associate from the drop down list or "(none)" if you want to remove the association.

Screenshot - UIAssociationsPropertyExtender.png

Figure 4: Edit UI item associations using property extender

Handling Execute and Update

To handle execute and update events, add event handlers to the "ApplicationCommandExecute" and "ApplicationCommandUpdate" events on the UISwitchboard component. These event handlers receive an "ApplicationCommandEventArgs" argument that contains information about the command and item that triggered the event. By checking these properties, you can update the command or item and execute the appropriate methods in your code. The code example below shows a generic execution handler, which displays available information in a message box when the command is executed.

C#
private void toolStripExtensionCommandSwitchboard1_CommandExecute(
    object sender, ApplicationCommandEventArgs e)
{
    Control owner = sender as Control;
    ApplicationCommand command = e.ApplicationCommand;
    ToolStripItem item = e.Item as ToolStripItem;
    string ownerName = "null";
    if (owner != null)
    {
        ownerName = owner.Name;
    }
    string itemName = "null";
    if (item != null)
    {
        itemName = item.Name;
    }

    System.Windows.Forms.MessageBox.Show("G Executing command:" +
        command.ApplicationCommandName + " owner:" + ownerName +
        " item:" + itemName);
}

The code example below shows how the update handler updates UI items based on application state.

C#
private void toolStripExtensionCommandSwitchboard1_CommandUpdate(
    object sender, ApplicationCommandEventArgs e)
{
    Control owner = sender as Control;
    ApplicationCommand command = e.ApplicationCommand;
    ToolStripItem item = e.Item as ToolStripItem;

    switch (command.ApplicationCommandName)
    {
        case "New":
            e.ApplicationCommand.Enabled = checkBoxEnableNew.Checked;
            break;
        case "FileCopy":
            e.ApplicationCommand.Enabled = checkBoxEnableGlobalCopy.Checked;
            break;
        case "ContextCopy":
            e.ApplicationCommand.Enabled = checkBoxEnableLocalCopy.Checked;
            break;
        case "Save":
            e.ApplicationCommand.Visible = checkBoxShowSave.Checked;
            break;
        case "TrackBar":
            toolStripProgressBar1.Value = toolStripTrackBar1.Value * 10;
            break;
    }
}

You can also add handlers for these events directly on an application command, if it is easier to handle a command in a specific event handler instead of the global event handler.

Associating Context Menus

Context menus need to be associated with the UISwitchboard component. if you want to update the context menu UI items when the context menu is shown. You have to associate the context menu with the UISwitchboard. You can use either the smart tag menu on the component or the component properties to open the "Context menus Association Editor." You can now add or remove context menus from the associated list.

Screenshot - EditContextMenuAssociations.png

Figure 5: Edit context menu associations

.NET 2.0 UI Items Supported

The following UI items are supported for .NET 2.0:

  • ToolStripItem
  • ToolStripButton
  • ToolStripLabel
  • ToolStripComboBox
  • ToolStripTextBox
  • ToolStripProgressBar
  • ToolStripDropDownItem
  • ToolStripMenuItem
  • ToolStripSplitButton
  • ToolStripDropDownButton
  • ToolStripStatusLabel
  • ContextMenuStrip

.NET 1.x UI Items Supported

The following UI items are supported for .NET 1.0 and 1.1:

  • MenuItem
  • ToolBarButton
  • ContextMenu

Extensibility

The switchboard is designed to be extensible by using an adapter pattern. The adapter handles the tasks that require knowledge of the UI item implementations. I have included adapters for the old .NET 1.x menu and toolbar classes, as well as for the .NET 2.0 menu and toolbar classes. It should be easy to write an adapter for a third party menu and toolbar package. Because the design-time support instantiates a component when loading the form, you also have to provide a specific UISwitchboard derived class which instantiates the correct adapter in the constructor. It is also possible to extend one of the existing adapters for supporting your own custom menu or toolbar controls, in addition to the standard controls. The source code includes an example of this extension.

Design-time Support

The goal for this component was to make it easy to add application commands and connect them to user interface items. The solution is design-time support. The design-time support should automate tasks such as finding all UI items available and presenting them in an easy-to-use user interface.

UISwitchboard Designer

A component with design-time support requires a designer. The UISwitchboardComponentDesigner class implements the required functionality for supporting the UISwitchboard component.

Smart tags

Similar to Office smart tags, Visual Studio smart tags make common tasks available that apply to the context of your work. The component designer class provides support for defining the commands that shall be available as smart tag commands.

Application Commands

Application commands are edited through the "ApplicationCommand collection editor." This design-time form provides support for creation, deletion and editing of application commands.

Screenshot - ApplicationCommandCollectionEditor.png

Figure 6: Application command collection editor

UI Item Associations

Each UI item needs to be associated with an application command. This design-time form provides support for associating a UI item with the current application command.

Screenshot - UIItemAssociationEditor.png

Figure 7: UIItem association editor

Property Extender

It is also possible to associate an item from the item properties. I use a property extender to add a property to each supported item, which lets you select an application command.

Points of Interest

Two major revelations occurred during this programming exercise, in addition to lots of small ones:

  • Design-time objects always need to inherit from the Component class. This will enable all design-time support to work as if by magic. Without this inheritance, strange things happen.
  • Properties of components always need both a get and set method to be serialized at design-time.
  • I had a hard time finding information about some of the design-time features. When I at last used Reflector to examine the Microsoft SplitterPanel component, then everything was easy and I needed only a few lines of code to make everything work.

I have generated a reference manual via Sandcastle and SandcastleBuilder. This is included in the source download.

Terms and Conditions

The UISwitchboard component is provided as free software with source code provided. You can freely use it in your applications, commercial or non-commercial. Bjørn Sundby, the author of the component, owns the copyright of the component and is not responsible for any damage in your application caused by using this component, directly or indirectly.

History

2007.05.01

  • Original article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)