n our previous article "Put a 24-hour Lockdown on Your .NET UIs
," we discussed various ways to augment user interfaces to interpose underlying business logic and data engine security constraints. We recommended the use of extender controls. The purpose behind this suggestion was clear: We don't like to code. In fact, if given a choice between coding and surfing, only one question remainswhere's the wax? While it is certainly possible and in some cases necessary to subclass existing controls, we prefer to reserve such methods for situations just shy of thermonuclear destruction.
However, one thing we did not expect when we made our suggestion was that some of our readers would be unfamiliar with the details of extender controls, their creation, and their operation. While such a discussion was outside the scope and coverage of the original article, we decided that it would make a fine subject for whole new article. So without further gilding the lily and with no more ado, we present to you our champion, the Knight of the Lazy Programmer, the Extender Control.
Extender Controls: What Are They
An extender control is a non-visual control (one added to the tray area of a form rather than the form itself) that "extends" the functionality of the Visual Studio designer. MSDN defines an extender provider control as: a component that provides properties to other components. For example, when a ToolTip Component (Windows Forms) component is added to a form, it provides a property called ToolTip to each control on that form. The ToolTip property then appears in the Properties window for each control and allows the developer to set a value for this property at design time." In short, extender controls are a short cut. They allow the VS designer to extend the displayed properties of a control so that from your standpoint the control is different. It's sort of like putting a new air freshener in your old Chevythe car doesn't run any better but it sure smells nice.
The important distinction however, is that extender controls only simulate the extension of properties to the control during design time. At runtime, any attempt to access the property as a member of the "extended" control will not run (in fact it will not even compile). The control is no different, just like that old Chevy. To access the methods and properties of the "extended" control at runtime, you must enumerate the extended properties and methods of the non-visual extender control itself.
Developing an Extender Control
An extender control, or, extender provider, if we want to get literal, is a component derived from System.ComponentModel.Control that implements the IExtenderProvider interface.
public class SecurityEnableComponent : System.ComponentModel.Component,
The interface itself is extraordinarily simple and merely requires the implementation of one method: "CanExtend." The development environment calls the Can Extend to determine whether a given control can be extended by the extender control. In most instances, the implementation of this method is accomplished through a very simple type check and only when it's necessary to prevent the extender from accidentally being applied to controls for which it is inappropriate or incapable of servicing. The code below shows an example of the "CanExtend" method from the SecurityEnableComponent
control discussed in the previous article
. Notice that the implementation of this method tests the type of an object provided by the caller and returns true if the target is either a Control or a Menu Item. This ensures that the Extender is only visible in the design-time properties for those categories of components and ignores all other types of components. The additional check (target is not SecurityEnableComponent
) in this instance is superfluous because the class is derived from Component and not Control. Nonetheless, it is good form and occasionally necessary for some implementations. It's purpose is to ensure that the extender is not used to extend itself.
bool IExtenderProvider.CanExtend(object target)
if((target is Menu || target is Control) && !(target is SecurityEnableComponent))