Share via


Command Management

Use Design Patterns to Simplify the Relationship Between Menus and Form Elements in .NET

Michael Foster and Gilberto Araya

Code download available at:CommandManagement.exe(55 KB)

This article assumes you're familiar with C# and Windows Forms

Level of Difficulty123

SUMMARY

In Windows Forms applications, similar commands, such as those in a menu and their counterparts on a toolbar, are not automatically related. They don't fire the same event or run the same handler routine. Yet code that allows the same or similar user commands to fire the same code simplifies development.

This article describes the principles of command management and why it's important to have functional commands that are not exclusive to any one UI element. In order to provide an MFC-like command management infrastructure, a design pattern is developed and applied as a series of C# classes.

Contents

Event Handling in .NET
Logical Notion of a Command
The Command Manager
Command State
Implementing a Command Manager in .NET
Command Executor
CommandManager Internals
Command Object Internals
CommandExecutor Implementation
Command Updates in Idle Processing
Sample Application
Conclusion

Command management is a popular feature among application frameworks because it has a number of useful applications. For example, command management allows you to have a single handler that can react to similar menu and toolbar events. In addition, the business logic for handling the command can be centralized in one location, rather than spread out in a variety of functions. Key to command management is the command manager, the central repository for all of the commands available in an application. The command manager's job is to provide a mechanism for an application to maintain a list of commands, perform operations on the commands, and respond to command events. The application can dynamically add or remove commands, as well as iterate through the set of available commands. The ability to iterate through the commands provides the infrastructure for an application to implement dynamic menu or toolbar configuration.

Many of the features of command management are included in the application frameworks provided by Microsoft® Foundation Classes (MFC). MFC, in particular, allows for the association of an OnUpdate method for each command so there can be a centralized location to set the state of the command (enabled, disabled, or checked) based on the state of other objects within the app.

With Windows® Forms, Microsoft has introduced a new framework for developing Windows-based applications. It provides a mechanism for interacting with menus and toolbars, as well as an event-centered notification system. Unlike MFC, however, Windows Forms does not provide centralized command management. Items on a menu have no correlation to similar items on a toolbar. They do not share a common ID and they do not fire similar events. Although Microsoft .NET-centric applications live on top of a different framework than MFC applications, the features of a command manager would still be highly desirable when writing applications using.NET.

In this article, we will discuss the set of features provided by a typical command management system, briefly describing how MFC provides these features. We will then discuss how to work with commands in .NET and the problems associated with this mechanism. Finally, we will implement a command manager for .NET that provides all of the features common in command management systems.

Event Handling in .NET

In traditional Windows- and MFC-based programs, the notion of a command is rudimentarily represented by Command IDs. As you may remember, a Command ID is a numeric value that is passed as a parameter to the WM_COMMAND message handlers. Objects such as menus and controls such as buttons can be defined to trigger WM_COMMAND messages with a particular Command ID as one of its arguments.

Although not exactly an object encapsulation of the request itself, the Command ID at least acts as a unifying force that allows the programmer to establish a logical relationship between UI elements associated with the same action. In addition, MFC provides UI update handlers, which support the ability to control the state of a command while the application is idle.

The .NET Framework provides a whole new rich environment for building applications for Windows. Although a great deal of attention is directed to the Web Services side of the .NET environment, Microsoft has also provided a fully object-oriented programming platform for creating rich Windows-based applications.

Instead of messages, .NET objects send notifications through events. Events are first-class citizens in the .NET environment. Contrast this with COM, where the definition of events through the connection points architecture was always a source of problems and confusion. .NET-enabled languages such as C# provide syntactical constructs to define event elements naturally.

.NET events present some advantages when compared with the message-based native Windows counterpart. First, they represent a more object-oriented approach, as any arbitrary object can subscribe to events. Remember that in Windows programming, only windows could receive messages. MFC improved on this with the ability for document and view objects to participate in the message-routing algorithm, but the event-based approach is a more flexible alternative. The second advantage of .NET events is that they allow multicasting. This means that multiple objects can subscribe to a particular notification, and when the event actually occurs, all subscribers will be notified without needing to have explicit knowledge of each other.

Unfortunately, despite this nice, object-oriented architecture, the notion of commands as objects does not exist in Windows Forms. Moreover, in isolating the developer from the underlying message-based nature of Windows, not even the notion of Command IDs exists anymore to act as that unifying identifier for each application action mentioned earlier.

In the next section we will make the case for why such functionality is desirable, and then proceed to provide an implementation for command management in .NET.

Logical Notion of a Command

The notion of encapsulating commands as objects is not new. An excellent discussion of this topic is offered as part of the Command design pattern in the classic treatise Design Patterns by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley, 1995).

A command represents a logical encapsulation of a request. In most cases, these requests are triggered by elements in the application's user interface, such as menu items or toolbar buttons, but they can also be executed from macros or external sources, or even be executed programmatically.

Why, then, would you want to encapsulate application commands as separate objects in their own right? The main benefit to this approach is that it separates the action request from the UI objects that trigger that action.

A command may have multiple physical representations in an application. For example, most document-oriented applications provide a Save operation that allows the user to persist the state of a document to a file. This operation might be deployed as an item on a menu, a button on a toolbar, or as a keyboard combination. Without the notion of a Save command, these UI elements are completely independent of each other; they fire separate notifications and have their separate states.

Separating the concept of a command entity from its visual manifestations in the application UI allows you to provide both a unified handler for each logical action and a centralized management of the command state.

Let's continue with the Save example. Without a command object, you would have to subscribe to the Click event for the menu item object and to the ButtonClick event for the toolbar, and add the corresponding code in both places. Even if both event handlers delegate to a single common routine that performs the actual work, it is the developer's responsibility to ensure that the same action is executed in response to both events. The framework itself does not enforce this. For example, it is conceivable that two completely different actions would take place, depending on the UI element used to select the Save action. Granted, this would most likely be a bug rather than the desired behavior, but errors like this are not uncommon when a programmer has the responsibility of manually providing a common handler.

If a Save Command entity existed, the application code would only need to subscribe to the event triggered by this command instance, which would be fired whenever the Save action was triggered by the user, regardless of how this actually occurred.

A command may also have an associated state whose value usually depends on the application context. Let's examine the familiar Copy command provided in most applications to facilitate copying the selected content to the system clipboard. It is common for this command to be in its Enabled state only when there is a selected item in the current application context.

Let's suppose that the application contains a listbox control. The Copy action should be possible whenever a valid item in the listbox is selected and the listbox has focus. If the listbox loses focus or does not contain a valid selection, the Copy action should not be available to the user. This means that all UI objects that trigger that action should be in a disabled state. The application might have an event handler that is invoked when the selection state of the listbox changes, and another event handler when the listbox loses focus. Without the separation of commands from the UI elements, the application would have to write code similar to the following in each of the handlers:

Toolbar.Buttons("Copy").Enabled = false mnuCopy.Enabled = false

As you can see, the listbox handlers must have specific knowledge of all application actions that depend on the state of the listbox, as well as the available UI elements that represent those actions. After encapsulating the actual request in a command object, the developer might instead write code like the following:

CommandManager.Command("Copy").Enabled = false

This would result in the automatic updating of all physical representations of the command. A command management framework should provide a mechanism to update the state of all command representations in one place. A single request to disable a command should automatically update all user interface elements associated with the command. It would be rather tedious to write the logic required to disable a menu item, a toolbar item, and any custom representations.

Imagine if you enabled the user to customize the layout of your toolbars and menus, as many commercial applications do today. In this scenario, the existence of all UI representations for a given command would not be known at design time. Therefore, there would simply be no way to write individual event handlers for each button, nor would it be possible to enumerate all UI elements in order to modify their state individually.

The Command Manager

As we mentioned earlier, the command manager is a central repository for all of the commands available in an application. Once commands are added to the command manager, the application needs to associate the command with UI elements. As mentioned in the Copy example, a single command can have multiple UI representations other than the typical menu items or toolbar buttons. One of the goals of the proposed architecture is to be open, so that application-specific widgets or third-party controls can be associated with commands. Those objects should integrate with the command manager as easily as the traditional menu and toolbar objects do. It is the command manager's job to maintain the association of a command with all of its UI representations.

The traditional way to respond to a command is to write an event handler for each UI element. If both a toolbar button and a menu item represent a command, then two distinct event handlers would be required. Each handler could then delegate to a common method to perform the necessary business logic. With a command management infrastructure, event handlers are associated with the command as opposed to the UI elements. One handler can then control all UI representations. If a new UI representation of a command were added to the application, the business logic for the event handler would not have to be modified in any way.

Although the command is usually triggered through standard UI controls, it may be desirable to programmatically trigger the command in response to a sequence of events that is not represented by a menu or toolbar. The command manager should allow a command to be executed through an API, which in turn allows all of the registered event handlers to execute.

Command State

The common states of a command are enabled, disabled, and checked. As described in the Copy example, the command manager should provide a mechanism to update the command state so that the new state is propagated to all user interface representations of the command.

The application is responsible for managing the state of a command. The command object should expose methods that allow an application to configure the state. The state should automatically reflect itself in all of the UI representations of the command.

In the previous example, the Copy command is enabled whenever the listbox has focus and a valid selection. When the listbox changes its focus state or its selection state, the application will need to make a call to the command manager to update the state of the command. The problem is that the business logic that defines the state rules for the command is distributed. Figure 1 shows the pseudocode required to manage the state in this scenario.

Figure 1 Distributed Command State

void OnListboxSelectionChanged() { UpdateCopyCommand(); } void OnListboxFocusChanged() { UpdateCopyCommand(); } void UpdateCopyCommand() { bool bListboxFocus = listbox.HasFocus(); bool bValidSelection = (listbox.GetSelection() != -1); CommandManager.Commands("Copy").Enable = bListbox && bValidSelection; }

As you can see, the business logic behind the Copy command state is encapsulated in UpdateCopyCommand. However, the application still needs to know all the places that could affect the Copy command state and be sure to invoke the common Update method from each location.

A command manager should allow commands to be updated during idle processing. During this time, the command manager will loop through all of its commands and fire a single Update event associated with the command. This is the approach that MFC takes. With this approach, the logic behind a command state is encapsulated in a single location and it does not depend on making calls to the handler from every application event that could possibly affect the command state.

Implementing a Command Manager in .NET

Figure 2 shows the objects involved in the command manager implementation and their relationships. The orange objects represent stock .NET objects and the blue objects represent the objects implemented as part of the command manager.

Figure 2 Command Manager Objects

We have already talked about the concepts of a command manager and a command object. Before we drill down into the implementation of these objects, we'll first introduce the concept of a command executor.

Command Executor

As stated previously, one of the goals of the command management architecture is that it should work well with any potential UI element that can be used to make commands accessible to users. Examples presented in the article are limited to menu items and toolbar buttons because these are very common and are part of the standard Windows Forms namespace. However, there should be a mechanism to plug any third-party widget into the architecture.

In order to achieve this goal, the command objects themselves cannot have explicit knowledge of the types that can be used in the UI to represent that command. Doing so would defeat this extensibility goal, as every control probably provides a different outgoing interface to communicate events, as well as different properties that represent the command state.

The CommandExecutor class acts as a bridge between command instances and their UI representations. As shown in Figure 2, CommandExecutor is an abstract base class that exposes the interface necessary for the command to manipulate the state of the controls. It is expected that there will be a subclass of the CommandExecutor class for each type that can act as a source of requests in the form of commands. The downloadable code that accompanies this article includes two implementations of this: MenuCommandExecutor and ToolbarCommandExecutor.

The responsibilities assigned to CommandExecutors include:

  1. Managing a list of all UI instances of their corresponding types, along with their command association.
  2. Subscribing to the events generated by the UI objects, and communicating them back to the command object.
  3. Encapsulating the specific interface to control the state display on its UI object type.

CommandManager Internals

Now, let's look at the implementation. The source for the CommandManager object can be found in Figure 3. To begin with, the command manager maintains two internal collections: commands and hashCommandExecutors.

Figure 3 Excerpts from CommandManager.cs

using System; using System.Collections; using System.Timers; using System.Windows.Forms; namespace CommandManagement{ public class CommandManager : System.ComponentModel.Component{ // Member Variables private CommandsList commands; private Hashtable hashCommandExecutors; // Constructor public CommandManager(){ commands = new CommandManager.CommandsList(this); hashCommandExecutors = new Hashtable(); // Setup idle processing Application.Idle += new EventHandler(this.OnIdle); // By default, menus and toolbars are known RegisterCommandExecutor( "System.Windows.Forms.MenuItem", new MenuCommandExecutor()); RegisterCommandExecutor( "System.Windows.Forms.ToolBarButton", new ToolbarCommandExecutor());} // Commands Property: Fetches the Command collection public CommandsList Commands{ get{ return commands; } } // Command Executor association methods internal void RegisterCommandExecutor( string strType, CommandExecutor executor){ hashCommandExecutors.Add(strType, executor);} internal CommandExecutor GetCommandExecutor(object instance){ return hashCommandExecutors[instance.GetType().ToString()] as CommandExecutor;} // Handler for the Idle application event. private void OnIdle(object sender, System.EventArgs args){ IDictionaryEnumerator myEnumerator = (IDictionaryEnumerator)commands.GetEnumerator(); while ( myEnumerator.MoveNext() ){ Command cmd = myEnumerator.Value as Command; if (cmd != null) cmd.ProcessUpdates();} } } // end class CommandManager } // end namespace

Commands is a collection of all the commands available in the application. Each command has a unique user-specified tag that distinguishes it from all other commands. The CommandsList object is a type-safe collection that implements the ICollection and IEnumerable interfaces. The collection allows for the enumerations of commands or for direct indexing of the command by its unique tag. The implementation of the CommandsList class has been excluded from the CommandManager code, since it is a boilerplate collection. The full source code can be found in the code download.

HashCommandExecutors is a hash table which stores all available CommandExecutors used in an application. Remember that there is one CommandExecutor for each UI type that can represent a command. The CommandExecutor is the glue that links command objects with their physical representations.

The CommandManager constructor sets up the default functionality. In addition to creating the internal data structures, it performs two other functions. First, an event handler is created to respond to the application's idle processing cycles.

Application.Idle += new EventHandler(this.OnIdle);

Second, CommandExecutors are created for MenuItems and ToolBarButton objects. The CommandManager has internal support for these two traditional UI objects. Applications are free to implement additional CommandExecutors. We will look at the code behind the CommandExecutors later in this article.

The RegisterCommandExecutor method is used to associate a CommandExecutor with a Windows control type.

RegisterCommandExecutor( "System.Windows.Forms.MenuItem", new MenuCommandExecutor() ); RegisterCommandExecutor( "System.Windows.Forms.ToolBarButton", new ToolbarCommandExecutor());

It maintains the association in the hashCommandExecutors hash table, as shown in the following code:

internal void RegisterCommandExecutor(string strType, CommandExecutor executor) { hashCommandExecutors.Add(strType, executor); } internal CommandExecutor GetCommandExecutor(object instance) { return hashCommandExecutors[instance.GetType().ToString()] as CommandExecutor; }

Here, the GetCommandExecutor method is used to retrieve the CommandExecutor associated with a specific UI control.

Command Object Internals

The source for the command object can be found in Figure 4. The command object constructor initializes the internal state of the object. The unique identifier for the command object is strTag. The event handlers for the OnUpdate and the OnExecute events are handlerExecute and handlerUpdate. Additional handlers can be specified using the standard event subscription syntax. The OnUpdate event is triggered during idle processing cycles to give the applications an opportunity to update the state of the command. The OnExecute event is triggered when a command is executed, either programmatically or through interaction with its UI representation.

Figure 4 Excerpts from Command.cs

using System; using System.Collections; using System.Timers; using System.Windows.Forms; namespace CommandManagement{ public class Command{ // Members private CommandInstanceList commandInstances; private CommandManager manager; private string strTag; protected bool enabled; protected bool check; // Constructor public Command( string strTag, ExecuteHandler handlerExecute, UpdateHandler handlerUpdate){ commandInstances = new CommandInstanceList(this); this.strTag = strTag; OnUpdate += handlerUpdate; OnExecute += handlerExecute;} // CommandInstances collection public CommandInstanceList CommandInstances{ get { return commandInstances; } } // Tag: Unique internal name for each command public string Tag { get {return strTag; } } // Manager property: maintain association with parent command manager internal CommandManager Manager{ get { return manager;} set{ manager = value; } } public override string ToString(){ return Tag;} // Methods to trigger events public void Execute(){ if (OnExecute != null) OnExecute(this);} internal void ProcessUpdates(){ if (OnUpdate != null) OnUpdate(this);} // Enabled property public bool Enabled { get{ return enabled;} set{ enabled = value; foreach(object instance in commandInstances){ Manager.GetCommandExecutor(instance).Enable( instance, enabled);} } } // Checked property public bool Checked{ get{ return check;} set{ check = value; foreach(object instance in commandInstances){ Manager.GetCommandExecutor(instance).Check( instance, check);} } } // Events public delegate void UpdateHandler(Command cmd); public event UpdateHandler OnUpdate; public delegate void ExecuteHandler(Command cmd); public event ExecuteHandler OnExecute; } }

The events are defined here:

public class Command { public delegate void UpdateHandler(Command cmd); public event UpdateHandler OnUpdate; public delegate void ExecuteHandler(Command cmd); public event ExecuteHandler OnExecute; }

In the constructor, you will also see that a collection called commandInstance is initialized. The collection maintains a link between the command and all of its UI representations. UI elements can be added to the collection one at a time, or as a group, through the Add methods (see Figure 5). The item in these methods is the actual UI element representing the command, usually a MenuItem or a ToolbarButton object. The full implementation of the CommandsInstanceList collection is in the code download.

Figure 5 Using Add

public class CommandInstanceList : System.Collections.CollectionBase { public void Add(object instance) { this.List.Add(instance); } public void Add(object[] items) { foreach (object item in items) { this.Add(item); } } }

The command object exposes Enabled and Checked properties to control the command state. The implementation of these properties is included in Figure 4, but take a close look at the Set attribute of the Command object's Enabled property, shown here:

public bool Enabled { set { enabled = value; foreach(object instance in commandInstances) { Manager.GetCommandExecutor(instance).Enable( instance, enabled); } } }

The code in this snippet loops through each UI element associated with the command. For each UI element, we look up the CommandExecutor associated with it. We then call its Enabled method so it can perform the UI control-specific logic associated with the state change request. The code for the Checked command behaves similarly.

CommandExecutor Implementation

The CommandExecutor base class defines the Enable and Check abstract methods that each derived class must implement to provide UI-specific logic. The source for the CommandExecutor class is shown in Figure 6. The CommandExecutor also contains some internal utilities. A hash table is implemented to maintain a mapping between all UI elements of a particular type and the corresponding command object associated with the UI element.

Figure 6 CommandExecutor Base Class

using System; using System.Collections; using System.Timers; using System.Windows.Forms; namespace CommandManagement{ // Command Executor base class public abstract class CommandExecutor{ protected Hashtable hashInstances = new Hashtable(); public virtual void InstanceAdded(object item, Command cmd){ hashInstances.Add(item, cmd);} protected Command GetCommandForInstance(object item){ return hashInstances[item] as Command;} // Interface for derived classed to implement public abstract void Enable(object item, bool bEnable); public abstract void Check(object item, bool bCheck);} }

The InstanceAdded method is called whenever a UI element of the associated type is added to the command's instance list through one of its Add methods. The CommandInstanceList collection contains the following piece of glue that links the command objects with the UI elements:

public class CommandInstanceList : System.Collections.CollectionBase { protected override void OnInsertComplete( System.Int32 index, System.Object value) { command.Manager.GetCommandExecutor(value).InstanceAdded(value, command); } }

The CollectionBase object calls OnInsertComplete after an item is inserted into the collection. As you can see, the CommandExecutor associated with the UI element is retrieved and its InstanceAdded method is called.

Figure 7 contains the implementation of the Menu and Toolbar CommandExecutors. The implementations are straightforward. The MenuCommandExecutor implements the abstract methods Enable and Check. The UI object is cast to a MenuItem, at which point the MenuItem's Enabled or Checked properties can be set. The ToolbarCommandExecutor code is similar:

public override void Enable(object item, bool bEnable) { MenuItem mi = (MenuItem)item; mi.Enabled = bEnable; } public override void Check(object item, bool bCheck) { MenuItem mi = (MenuItem)item; mi.Checked = bCheck; }

Figure 7 Menu and Toolbar Command Executors

using System; using System.Collections; using System.Timers; using System.Windows.Forms; namespace CommandManagement{ // Menu command executor public class MenuCommandExecutor : CommandExecutor{ public override void InstanceAdded(object item, Command cmd){ MenuItem mi = (MenuItem)item; mi.Click += new System.EventHandler(menuItem_Click); base.InstanceAdded(item, cmd);} // State setters public override void Enable(object item, bool bEnable){ MenuItem mi = (MenuItem)item; mi.Enabled = bEnable;} public override void Check(object item, bool bCheck){ MenuItem mi = (MenuItem)item; mi.Checked = bCheck;} // Execution event handler private void menuItem_Click(object sender, System.EventArgs e){ Command cmd = GetCommandForInstance(sender); cmd.Execute(); } } // Toolbar command executor public class ToolbarCommandExecutor : CommandExecutor{ public override void InstanceAdded(object item, Command cmd){ ToolBarButton button = (ToolBarButton)item; ToolBarButtonClickEventHandler handler = new ToolBarButtonClickEventHandler(toolbar_ButtonClick); // Attempt to remove the handler first, in case we have already // signed up for the event in this toolbar button.Parent.ButtonClick -= handler; button.Parent.ButtonClick += handler; base.InstanceAdded(item, cmd);} // State setters public override void Enable(object item, bool bEnable){ ToolBarButton button = (ToolBarButton)item; button.Enabled = bEnable;} public override void Check(object item, bool bCheck){ ToolBarButton button = (ToolBarButton)item; button.Style = ToolBarButtonStyle.ToggleButton; button.Pushed = bCheck;} // Execution event handler private void toolbar_ButtonClick( object sender, ToolBarButtonClickEventArgs args){ Command cmd = GetCommandForInstance(args.Button); cmd.Execute(); } } }

The MenuCommandExecutor also overrides the InstanceAdded method and registers a handler for the MenuItem's Click event:

public override void InstanceAdded(object item, Command cmd) { MenuItem mi = (MenuItem)item; mi.Click += new System.EventHandler(menuItem_Click); base.InstanceAdded(item, cmd); }

When a menu item is selected, its Click event is fired and the menuItem_Click handler is called. The MenuCommandExecutor looks up the Command associated with the menu item and calls its Execute method which, in turn, will call each of the handlers associated with the Command's OnExecute event:

private void menuItem_Click(object sender, System.EventArgs e) { Command cmd = GetCommandForInstance(sender); cmd.Execute(); }

Command Updates in Idle Processing

We have already examined how Check and Enable properties control the state of the command, but there is one final piece to this puzzle. As discussed earlier, it is desirable to encapsulate the state of a command so the application will not have to distribute this knowledge to all of the places that can affect the state of the command. Earlier, we saw that the CommandManager implemented a handler for the application's Idle event, but let's look at the details behind that handler:

private void OnIdle(object sender, System.EventArgs args) { IDictionaryEnumerator myEnumerator = IDictionaryEnumerator)commands.GetEnumerator(); while ( myEnumerator.MoveNext() ) { Command cmd = myEnumerator.Value as Command; if (cmd != null) cmd.ProcessUpdates(); } }

When the idle processing handler is triggered, the command manager iterates through the commands. For each command, it will trigger the Update event, which allows the application to configure the state of that command.

Sample Application

To illustrate the usage of the classes we have introduced up to this point, let's look at a simple application that uses the command management features.

The sample that accompanies this article features a window with a RichEdit control. There are five commands available, and they can be executed from menu items or from buttons on the toolbar. Figure 8 shows the sample editor.

Figure 8 The Editor

Figure 8** The Editor **

The first thing that the editor must do is to create the initial commands and link them to their respective UI representations. The following code sample creates a Copy command and associates it with its corresponding menu item in the menu and also with a toolbar button:

private void InitializeCommandManager() { cmdMgr = new CommandManager(); cmdMgr.Commands.Add( new Command( "EditCopy", new Command.ExecuteHandler(OnCopy), new Command.UpdateHandler(UpdateCopyCommand))); cmdMgr.Commands["EditCopy"].CommandInstances.Add( new Object[]{mnuEditCopy, tlbMain.Buttons[4]}); }

The Copy command illustrates the advantages of having the Update event triggered during idle processing cycles. The enabled state of the Copy command depends on whether there is any text selected in the edit control. The OnUpdate event handler for the Copy command looks like this:

public void UpdateCopyCommand(Command cmd) { cmd.Enabled = txtEditor.SelectedText.Length > 0; }

A single line enables or disables both the Edit | Copy menu item and the Copy button in the toolbar, according to the selection state in the text editor.

The Bold command also illustrates the background update feature. When executed, this command toggles the Bold attribute of the font used in the editor for the text selected. Feedback about the value of this attribute is given to the user through the Checked state of the command. Therefore, the Checked attribute needs to reflect the state of the text over which the cursor is positioned:

public void UpdateBoldCommand(Command cmd) { cmd.Checked = txtEditor.SelectionFont.Bold; }

The other commands defined in this application are Open, Save, and Print. No real functionality is associated with these commands, but their common OnExecute handler illustrates how all requests of each type are redirected to same handler regardless of where they come from.

Conclusion

Command management helps to disassociate an application's business logic from its user interface. This produces clean, maintainable code, and opens the door for more advanced features to be built on top of the provided infrastructure.

For related articles see:
Design Patterns: Solidify Your C# Application Architecture with Design Patterns
Windows Forms: A Modern-Day Programming Model for Writing GUI Applications

Michael Foster and Gilberto Arayahave been developing Windows-based applications for more than 10 years. Their primary focus has been component architectures. You can reach Michael at mfoster9@yahoo.com. Gilberto can be e-mailed at gilber@nc.rr.com.