By your CommandThis article discusses a possible implementation for the command pattern (see GoF) in visual basic. It is written primarily to bring up some ideas. The idea of the “commands” in this article is that they allow for a central place to code “command execution logic”. The easiest way to explain this is by giving a simple example. Suppose you have a GUI application that puts up a screen. In the screen there are various widgets that allow the user to execute a certain command. In a list screen, it is not uncommon that there are multiple ways to accomplish the same. P.e. to open up a detail screen, a user might click a commandbutton “Open” at the bottom of the screen, double click on a given item in the list, right click on the list and select “open” from the popup menu, click a toolbar icon or click an item on a menu. The first problem is that all of these ways should perform the same code. The second problem is that all widgets should display consistently. If a given action is unavaible, it should be unavailable “everywhere on the screen”. So how could we do this ? First we need to decide how we will represent commands. There are basically two ways : either command is a fixed class or it is an interface. Making commands a fixed class is more appealing as it might seem to be at first. Commands could expose an event to execute them. This event code could be put into the form. To an average programmer, the code would look just the same as normal form event handling code. It would only differ in the wiring of the components. We could event present this class as a non-visual non-hWnd activeX control, which would have the benefit that the visual design-time image of your form contains a control for every command we need. Stubborn as I usually am, I decide to make command an interface. It has two benefits. First of all, it allows for the first approach too (class based). So it really “contains” the first approach as a sub-solution. But maybe more important is that by putting each command in its own seperate class there might be a tendency to reuse commands. Since code reuse is usually considered A Good Thing, I decided to go for this approach. ICommandHere is what my interface looks like : Interface iCommand The “Execute” method is obvious. It just executes the command. The other properties are less clear. Having a ‘Caption’, ‘TooltipText’ and ‘Enabled’ property seems odd for something that is supposed to be UI independent. The short story is that my commands are not in the business layer but in the window layer. If I would need business layer commands, there would be a separate interface (IBusinessCommand ?) with only the execute method. Since I want my commands to be observable (notify others of any changes) and since ICommand is an interface, I need an event channel object cCommandEvents which is used for sending events to observers. (See also interfaces withevents for other possibilities). Here is what the cCommandEvents class looks like : Public Event CaptionChanged(ByVal strNewCaption As String) LinksThis could be all there is to a command but unfortunately it is not. It would be quite unlogical not to have the common “binding” plumbing available. After all, we want to link these command objects to UI objects such as command buttons and menu items. Therefore we created some support classes. The following is the code for cLinkCommandoButton. It will keep a command button and an ICommand implementation synchonized : Private WithEvents mButton As CommandButton
One remark before we continue : the line “mButton.Enabled = bNewEnabled” could also be “mButton.Visible = bNewEnabled”. In that case you would hide the button when the command is not available. As normal, I also wrote a little “constructor” for this class : Public Function CreateCommandToButtonLink(ByVal aButton As CommandButton, ByVal aCOmmand As iCommand) As Object The only strange thing about this constructor is that it actually returns an “Object”. This has nothing to do with late binding. It is only one of those rare cases where the actual class that gets created is totally irrelevant. As a matter of fact, the class cLinkCommandToButton is a private class ! Needless to say, I also wrote a class cLinkCommandToMenuItem. An ExampleHere is a simple demo command class. It has the very useful (?) functionality of appending an asterix to the caption of a form : Private mForm As Form If we now have a form with both a menu and a Commandbutton, we could have the following initialization code : Dim mLinks As Collection As you can see, at form load time, I set up the links between the controls and the command. The only “surprise” is the links collection. This collection has only one purpose : prevent that the link objects are released before the form closes. By adding them to a collection we increase their reference count, which keeps them alive. An even more crucial aspect is that we have to release the links collection when the form is unloading. If we would not do this, we would create circular references between the form and our commands (indirectly). Remember the link objects have a reference to the visual controls. If we would not release them we could end up with a circular reference. Improvements and variationsIt is obvious that my ICommand favors certain visual properties (Caption, tooltipText). One could equally well include pictures in the properties. The reason I did not do this is that pictures tend to be needed in different sizes (toolbars and command buttons might need a different size of picture). Therefore, it made more sense (for me) to leave the pictures in the visual widgets themselves. It would be nice if each activeX control came with its own set of predefined commands. That would make reuse very simple. <more here> | ||||||||||||||||||||||||||||||||||
Subitems : | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
| Site updated : Monday, February 17, 2003
| ||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||