Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles
We take a look at planned support for parallel programming for both managed and native code in the next version of Visual Studio.

By Stephen Toub and Hazim Shafi (October 2008)
This month Scott shows how to generate realistic test data, visits Dare Obasanjo's blog, and demonstrates color coding code for better readability.

By Scott Mitchell (October 2008)
Learn how to use Windows Presentation Foundation (WPF), XAML, and the deep XML support in Visual Basic to generate user interfaces dynamically.

By Beth Massi (October 2008)
This month: memory access issues in multi-core systems and diagnosing and avoiding false sharing in your parallel computing applications.

By Stephen Toub, Igor Ostrovsky, and Huseyin Yildiz (October 2008)
More ...
Articles by this Author
There’s a strong similarity between Web-based Silverlight 2 applications and desktop WPF applications. Enabling easy code reuse between the two is Dino’s focus here.

By Dino Esposito (October 2008)
This month Dino builds a service layer that authenticates users of Silverlight 2 and ASP.NET AJAX services to prevent illegal access to sensitive back-end services.

By Dino Esposito (September 2008)
Dino Esposito compares the use of AJAX patterns and DOM manipulations to the use of the ASP.NET partial rendering engine.

By Dino Esposito (August 2008)
In this installment, the author provides an enhanced implementation of the BST pattern and compares it to HTM solutions.

By Dino Esposito (July 2008)
AJAX is meant to go beyond mere partial page rendering. Find out where Dino Esposito thinks dynamic pages are headed in the future with ASP.NET AJAX.

By Dino Esposito (June 2008)
This month we begin a look at the Single Page Interface (SPI) model and some design patterns for designing AJAX applications.

By Dino Esposito (May 2008)
This month, use nested ListView controls to create hierarchical views of data and extend the eventing model of the ListView by deriving a custom ListView class.

By Dino Esposito (April 2008)
This month Dino Esposito shows you how to get Windows-style modal dialog boxes for your Web applications thanks to the Ajax Control Toolkit and some clever coding.

By Dino Esposito (Launch 2008)
More ...
Popular Articles
Learn how to create a workflow that uses InfoPath forms and other office documents for passing data to targeted activities and for use in Office documents.

By Rick Spiewak (June 2008)
ADO.NET Data Services provide Web-accessible endpoints that allow you to filter, sort, shape, and page data without having to build that functionality yourself.

By Shawn Wildermuth (September 2008)
Here the author answers questions regarding the Entity Framework and provides an understanding of how and why it was developed.

By Elisa Flasko (July 2008)
In this article, author John Torjo presents a guide to his C++ GUI library called eGUI++ and explains how it makes user interface programming easier.

By John Torjo (June 2008)
More ...
Read the Blog
Long-running processes are common in distributed computing. Some business processes are made up of multiple execution sequences which may last many days or even weeks. In the October 2008 issue of MSDN Magazine, Juval Lowy discusses several techniques ...
Read more!
Correctly engineered concurrent code must live by an extra set of rules. Reads and writes from memory and access to shared resources need to be regulated so that conflicts do not arise. Additionally, threads often need to coordinate to get the job done. In the October 2008 issue of MSDN Magazine, Joe ...
Read more!
Well designed code keeps things that have to change together as close together in the code as possible and allows unrelated things in the code to change independently, while minimizing duplication in the code. In the October 2008 issue of MSDN Magazine, Jeremy Miller shows you some design ...
Read more!
The process for ink capture and analysis on the Tablet PC is straightforward in managed code. To the uninitiated developer, however, creating unmanaged Tablet PC applications can be rather daunting. In the October 2008 issue of MSDN Magazine, Gus Class a quick introduction to the Tablet PC ...
Read more!
Multicore systems are becoming increasingly prevalent, but the majority of software today will not automatically take advantage of this additional processing ability. And multithreaded programming, for anything but the most trivial of systems, is incredibly difficult and error prone today. In the October 2008 issue of MSDN ...
Read more!
Concurrent programming is notoriously difficult, even for experts. You have all of the correctness and security challenges of sequential programs plus all of the difficulties of parallelism and concurrent access to shared resources. In the October 2008 issue of MSDN Magazine, David Callahan describes ...
Read more!
More ...
Cutting Edge
Custom Provider Controls
Dino Esposito

Code download available at: CuttingEdge0311.exe (139 KB)
Browse the Code Online
Sometimes I find the Windows® Forms controls in Visual Studio® .NET to be lacking a particular feature that's indispensable to the application I'm building. While I'm not saying that the set of Windows Forms controls is inadequate, a general-purpose toolbox can't possibly meet all user requirements. Let's consider the TextBox control, for instance. It's relatively easy to agree on a minimum set of properties and methods that this control has to support. However, there is a large set of extended properties that would be very useful. For example, you might want the ability to change the background color when the control gets the focus, an input mask, or perhaps an associated autocomplete list. Of course, I'd rather have a lightweight control that can be extended than a bloated component that has all the features I'd ever need.
In Windows Forms, inheritance is just one option for building extended versions of existing controls. Another option involves provider controls, which is the subject of this month's column. Provider controls add new properties to existing controls without the need for inheritance. The idea is that you use an external extender control to provide new properties and behaviors to existing controls. The implementation of such extensions doesn't add weight to the base control; it's a lightweight alternative to inheritance. Provider controls don't replace inheritance; rather, they extend and complement it in many ways.

Derive a New Class
Suppose you want a textbox that changes its background color when it has focus. One option you have is to derive a new class. Figure 1 shows a simple class that inherits from TextBox and wires up the GotFocus and LostFocus events. The AutoColorTextBox class changes the background color when the control gets the focus and restores the original color when the LostFocus event is fired. You can easily assign different colors to each textbox. All you need to do is place instances of the AutoColorTextBox class on the form and set the background color when the control gets focus:
private void Form1_Load(object sender, EventArgs e)
{
   autoColorTextBox1.SelectedBackColor = Color.Cyan;
   autoColorTextBox2.SelectedBackColor = Color.Yellow;
   autoColorTextBox3.SelectedBackColor = Color.LightGreen;
}
Inheritance is an excellent choice if you need to customize the behavior and the appearance of controls. But what if you want to add another feature to your TextBox class? Suppose you want the textbox to accept only numbers and display all negative numbers in red. Figure 2 shows this new version of the control. The class AutoNumericTextBox inherits from the previously defined AutoColorTextBox. As long as you need both features in all textboxes, inheritance is fine.
Figure 2 The Modified Control 
However, what if you need to use extensions as individual attributes? As these controls are currently designed, all the features are loaded even if you need only the numeric mode (see Figure 3). An alternative scheme, in which extensions are managed individually, is at odds with the core idea of inheritance. With inheritance an object has all the features of the class. So if you want to be able to combine the basic features of the TextBox class with any possible extensions like auto-color and numeric mode, you need to build one of the following classes: TextBox+AutoColor, TextBox+Numeric, or TextBox+AutoColor+Numeric. Scale this pattern to meet the complexity (and the quantity) of real-world classes and you will understand why inheritance is not always the best option for extending controls .

Providers
A provider control lets you extend existing controls without creating new specific classes. The code that performs the extension (the GotFocus and LostFocus handlers) is loaded into an external class that plugs into the base class at run time. The excellent design-time support in Visual Studio .NET makes the presence of provider controls go almost unnoticed.
To get the numeric code and auto-color features, you need to write two provider controls; one implementing auto-color and one implementing the numeric mode. On the final form, place only the providers that you really need. This way, no unnecessary code is loaded. If you need to combine two or more extensions you can do it by binding more providers to the same control.
Provider controls prove to be extremely useful in another scenario as well. Consider again the extension that changes the background color of a TextBox control. What if you want to add that feature to RichTextBox and ListBox controls, too? Without providers, your only option would be to create two new classes.
The beauty of provider controls is that they allow you to extend multiple types of base controls. The ultimate role of providers is to add custom properties to existing controls. Extended properties show up in the Visual Studio .NET property grid. At run time the Windows Forms infrastructure yields control to the provider for the actual implementation of the extended properties. In doing so, the extender control gets a reference to the extendee and can check the type and the name as well as read and update the state.

The ToolTip Provider Control
Before I discuss how to build custom provider controls, let's review the predefined extenders that come with the Windows Forms toolbox: the ToolTip, HelpProvider, and ErrorProvider controls. All of them are displayed in the component tray area of the Visual Studio .NET IDE, as shown in Figure 4. Each provider control can have its own set of properties that affect the way in which the control works. The control-specific properties have nothing to do with the extensions that are added to bound controls.
Figure 4 Provider Control Icons 
The ToolTip control lists properties that let you configure the timing of the popup text, and the ErrorProvider control lets you change the icon used to represent the error message and make the text blink on demand. Finally, the HelpProvider control needs a compiled help file to work.
Figure 5 ToolTip Property 
Now that you've added a few extender controls to the form, select any other control in the form and scroll to its set of properties. You may be surprised to find that all controls in the form now feature an extra ToolTip property (see Figure 5). The exact name of the property in the grid is "ToolTip on toolTip1," where toolTip1 is the name of the extender control. Set this property for a textbox and build the project. The control on the form should now display a tooltip. Select a button and repeat the operation. The button also has a "ToolTip on toolTip1" property which, when set, causes a tooltip to appear when the mouse pointer hovers over the button. This means that the ToolTip extender control can extend virtually any control you may have on a form with the sole exception of another ToolTip control. Each control that can appear on a form is automatically given a ToolTip property which, if set, causes a popup description to appear at run time.
In this way, all controls that belong to the form share the same ToolTip object, which maintains an internal table of control/caption pairs. Like many other Windows Forms controls, the ToolTip control is a wrapper built around a Win32® window-based control. A Win32 tooltip window lives behind the managed ToolTip object. This window is created when the managed ToolTip object is instantiated and configured for style and delay. Next, a couple of internal tables are added—one to store control/caption associations and one to store control/region pairs.
If you're familiar with Win32 ToolTip controls you know that a single instance can be used to display popup descriptions at different screen locations. In other words, the way in which the ToolTip control works in Windows is significantly different from HTML tooltips, which are attributes bound to an individual element. The Visual Basic® 6.0 model is like the Web scenario. Visual Basic 6.0, in fact, gives each control a ToolTipText property. Don't judge this behavior by its appearance, however. The Visual Basic 6.0 mechanism is not really different from the Windows Forms model. In the Visual Basic 6.0 IDE, the ToolTipText property is an extended property that the ActiveX® container adds to any hosted control. Under the hood of this seemingly simple programming model, only one Win32 tooltip window is created and used to display text for each constituent element that features a non-empty caption. How can you get a tooltip window to display text whenever the mouse pointer stops over a given control? It's simple—use regions.
A tooltip region is a rectangular area that the tooltip is called to monitor. Whenever the mouse enters the area and stops there for the specified period of time, the ToolTip moves its window there, sets the caption, and pops it up. In Windows Forms, each control that has a non-empty caption also is given an entry in the region table. The region contains the bounds of the control area.

HelpProvider and ErrorProvider
The HelpProvider control gets into the game when the user presses the F1 key while the focus is on a form control. HelpProvider adds three properties to each control: HelpNavigator, HelpKeyword, and HelpString. HelpNavigator determines what happens when the user requests some help. The property accepts values from the HelpNavigator enumeration and provides access to specific elements of the help file. HelpKeyword indicates the keyword or the topic to be searched, while the HelpString is displayed through a tooltip, as shown in Figure 6. The HelpString property is independent from any help file and displays the tooltip when F1 is pressed.
Figure 6 Some Help Text 
The ErrorProvider displays an optionally blinking icon beside any control with an error message (see Figure 7). The properties added to each control respect the graphical styles of the icon—IconAlignment and IconPadding. By default, the icon is placed to the right of the control and centered vertically. No pixels are left as padding between the border of the control and the icon unless you set IconPadding to a nonzero value.
Figure 7 Error Icon 
The ErrorProvider control adds a third entry to each control's property grid—Error. The Error property contains the error message that the control will display. Unlike tooltips, which are seldom determined at run time, error messages are a dynamic property. This reveals an important difference between extender controls and inherited classes. The properties added to each control—say, the Error message—are not really new properties that you can set programmatically. You can set extended properties at design time because Visual Studio .NET performs this trick, not because real properties are dynamically added to controls. The following code doesn't compile and the reason is obvious—the Error property is not part of the programming interface of a TextBox, but you can set it at design time:
txtAge.Error = "Must be > 18"; 
So how can you set an error message or a tooltip caption dynamically? You do it using a method on the extender control. The previous line of code must be rewritten as follows:
errorProvider1.SetError(txtAge, 18);
You set the ToolTip text property at run time using nearly identical syntax:
toolTip1.SetToolTip(txtAge, "Enter a major age");
Is there a pattern behind this? An extender control must supply a pair of GetXxx/SetXxx methods for each Xxx property it adds to extendees. Using these methods, a control can access both properties at run time. The prototype of such methods is shown here:
public string GetError(Control control);
public void SetError(Control control, string value);
In these signatures the string type changes according to the actual type of the extended property.
Overall, extender controls are important for a couple of reasons. They provide an alternative model to extend existing controls which is orthogonal to class inheritance. Second, using extender controls wisely can significantly limit the amount of code you need to write for each form. What is the common foundation upon which extender controls must base their functionality? It's the IExtenderProvider interface.

The IExtenderProvider Interface
IExtenderProvider defines only one method—CanExtend. The interface is defined as follows:
public interface IExtenderProvider 
{
    bool CanExtend(object extendee);
}
Visual Studio .NET calls CanExtend to determine which objects in a container should receive the extender properties. Any component that provides extender properties must implement IExtenderProvider:
public class SimpleTextBoxExtender : Component, IExtenderProvider 
{
   •••
}
Aside from the fact that it implements the IExtenderProvider interface, an extender is primarily a control. For this reason, in addition to implementing the interface you must make it inherit the base functionality of a control. However, if you inherit it from Control, then the control can't be dropped in the component tray area—only on the form. To make it show in the component tray, use Component as the base class. In both cases, though, the overall behavior of the extender doesn't change much.
An extender provider class must be marked with a [ProvideProperty] attribute. The constructor of the ProvideProperty attribute class takes two arguments. The first parameter is the name of the property to add and the second is the type of the object to which you provide the property.
The following code snippet defines an extender that adds the SelectedBackColor property to all textboxes on the form:
[ProvideProperty("SelectedBackColor", typeof(TextBox))]
class SimpleTextBoxExtender: Component, IExtenderProvider 
{
   •••
}
Note that you can also declare the property as an extended property for virtually any component—using IComponent or Control instead of TextBox in the attribute. In this case, the implementation typically will include features that make it usable only with a specific category of controls.
You implement the CanExtend method so that it returns true for each control to which the extender wants to add properties. Here's a possible implementation for a simple TextBox extender:
public bool CanExtend(object extendee) 
{
   return (extendee is TextBox);
}
A similar implementation also catches any control that inherits from the TextBox class, including the custom classes I built earlier. Figure 8 shows the source code of a very simple extender control. It implements a background color change when the control is focused. In particular, the extender defines the pair of GetSelectedBackColor and SetSelectedBackColor methods. They can be called by any textbox to programmatically get or set the background color. In addition, the control features a public property, SelectedBackColor, which appears in the property grid and provides the default color. Notice that the property won't show up in the property grid if you don't explicitly implement it using the get/set accessors:
private Color m_SelectedBackColor;
public Color SelectedBackColor
{
    get {return m_SelectedBackColor;}
    set {m_SelectedBackColor = value;}
}
If you use this control in a sample application, it works just fine. However, when coded this way the control is too simple and not particularly functional. The main drawback is that the background color is unique for all textboxes. Furthermore, hooking events is a delicate operation that needs more attention. Try using any of the derived textboxes with the extender and you'll see that confusion results. Serious extenders need to maintain a table of bound controls and store settings individually.

Writing a Custom Extender Control
Let's enhance the simple TextBox extender to provide better support to each extendee. The extender will now add two properties—the background and foreground colors (see Figure 9).
Each extendee control is assigned an information class that's structured as follows:
public class TextBoxInfo
{
   public Color SelectedBackColor;
   public Color OldBackColor;
   public Color SelectedForeColor;
   public Color OldForeColor;
   public bool  EventsWired;
}
This class tracks the colors to use, but also the colors to restore and wires the GotFocus and LostFocus events only once, which is indicated by the EventsWired property. The code for the Get/Set pairs gets slightly more complicated. Let's tackle the Get accessor first:
public Color GetSelectedBackColor(Control control)
{
   // Retrieve related info
   TextBox t = (TextBox) control;
   TextBoxInfo info = (TextBoxInfo) Extendees[t];

   return info.SelectedBackColor; 
}
The control parameter references the actual extendee control—a TextBox in this case. Once you get a reference to the underlying control, you could also filter out controls based on the name or any other property you can access. You use the control reference as the key to access the hashtable and retrieve the corresponding TextBoxInfo structure. After that, returning the background color to use is child's play.
Who's creating the entry in the hashtable and when? The Set accessor of one of the properties is responsible for inserting the control in the table. The control won't be added if a similar entry already exists in the hash table. Figure 10 shows the source code of the SetSelectedBackColor method.

Extending the ToolTip Extender
The ToolTip class is sealed and can't be inherited to add more features such as the balloon style. In Windows XP and newer operating systems, the ToolTip window has been given the TTS_BALLOON style to display the caption in a balloon-style popup window. At first, deriving a new extender class from the existing ToolTip provider and adding support for the balloon style seems like a relatively easy task. The first problem you run into is that the ToolTip class is sealed; that is, it's not further inheritable. However, by using aggregation instead of inheritance you can devise a custom wrapper extender that exploits the underlying capabilities of the ToolTip class.
The idea is to create a new instance of the ToolTip class in the extender's constructor and call the GetToolTip and SetToolTip methods in the get and set accessors of the new ToolTip property.
[ProvideProperty("MyText", typeof(TextBox))]
public class MyToolTip : Component, IExtenderProvider
{
   private ToolTip _toolTip;
   public MyToolTip() 
   {
      toolTip = new ToolTip();
   }
   •••
}
The MyToolTip class embeds a dynamically created instance of the ToolTip class as a private property and exposes a MyText extended property. The implementation of this property passes through the implementation of the text property on the original ToolTip class:
public string GetMyText(Control control)
{
   return _toolTip.GetToolTip(control); 
}

public void SetMyText(Control control, string caption)
{
   // TODO :: Enter your changes...

   _toolTip.SetToolTip(control, caption);
}
By implementing this code, you end up with your own custom extender, making it work on top of the existing ToolTip component. A good reason for extending the ToolTip is to use a customized ToolTip control. Balloon and multiline styles are not supported by Windows Forms ToolTips and the only way to add these features is through a custom ToolTip extender. Unfortunately, of the three built-in extenders the one you need—the ToolTip component—is sealed and can't be inherited. That's why you must resort to the trick based on control aggregation.
However, the main obstacle on the road to full customization of the Windows Forms ToolTips lives elsewhere. The ToolTip control inherits from Component, not from Control. There's controversy over which way is better. If you inherit a class from Component, the class behaves like a control tray component, which would be great for extenders. If you derive the class from Control, the resulting component can't be placed in the IDE tray area. However, it will inherit the Handle property from the base class.
The Handle property represents the HWND handle of the underlying Win32 control. Since Windows Forms are based extensively on Win32 controls, they end up creating a window whenever a Control object is instantiated. To customize the appearance and behavior of a control, you need to resort to Win32 styles and messages. And how can you set them if you can't access the underlying window handle?
The managed ToolTip control does have a Handle property defined as an IntPtr member. Recall that IntPtr is the .NET Framework type that maps a Win32 handle such as HWND, HGLOBAL, or HKEY. The difficulty lies in the fact that the ToolTip's Handle property is declared as private and is thus inaccessible due to its protection level. The ToolTip class could be further extended using aggregation, but the extensions you can really add in practice are limited to anything you can do without knowing the HWND of the underlying ToolTip window.

Summing It Up
Extender controls represent an alternate route to control inheritance. By writing extenders you can achieve two goals. First, you can implement a finer level of granularity and decide what features to add to a class without creating a new class and inheriting features at run time. Second, you can add the same features to many control types using a single extension class. You could add properties to textboxes and comboboxes using a unique extender; if you used inheritance, that would require two distinct classes. In addition, while inheritance represents a pure coding approach, extenders try to shift some of the required burden at design time. Extenders reduce the amount of code you need to write and promote a model of programming that is more declarative and attribute based.
Remember, of course, extenders do not replace inheritance, but rather complement it and contribute to making your programming toolset richer than ever.

Send your questions and comments for Dino to  cutting@microsoft.com.


Dino Esposito is an instructor and consultant based in Rome, Italy. Author of Programming Microsoft ASP.NET (Microsoft Press, 2003), he spends most of his time teaching classes on ADO.NET and ASP.NET and speaking at conferences. Get in touch with Dino at cutting@microsoft.com.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker