Visual inheritanceis Microsoft's term for the ability of .NET forms and components to serve as base classes for other forms and components. Inheritance for forms and controls works in much the same way as inheritance for other .NET objects, so if you have a good understanding of inheritance, in general, you won't have much trouble using visual inheritance in your applications. The challenge, as always, lies in understanding when it's beneficial to use the technique.
In this article, I'll peel away some of the hype layers and show you the mechanics of using inheritance with forms, explain some good general uses of the technique, and provide you with a somewhat advanced example of how visual inheritance can simplify your code.
What's in a name?
Considering that all .NET GUI components are classes that themselves ultimately inherit from System.Object, their capability to serve as bases for other classes shouldn't be all that mind-blowing. Still, it's a neat new feature, so I can excuse Microsoft's marketing department for maybe getting a little overly excited when it chose a name. It has always seemed to enjoy copyrighting phrases that begin with the word "visual"—and besides, the term does lend itself to some great wordplay. Unfortunately, one of the drawbacks of choosing a geek-speak term like visual inheritance to describe a basic object-oriented technique is that such a name makes the behavior sound much more complicated than it actually is.
To create a form that inherits from another form, you use the same syntax you would use when inheriting from any other class. In VB.NET, this is the Inherits keyword. In C# or C++, the colon operator (:) designates inheritance. Creating a derived control works in a similar fashion. For example, the VB.NET and C# code to create a ChildForm form that inherits from the form ParentForm would look like this:
Public Class ChildForm Inherits ParentForm
Public Class ChildForm : ParentForm
Visual Studio will, of course, take care of this for you when you add a new item of type "Inherited Form" or "Inherited User Control" to your project. Check out a designer-generated code module, and you'll see this in the code.
At this point, ChildForm can override any public or protected members of ParentForm. In addition, any controls or components contained in ParentForm will be visible on ChildForm when it is displayed, either in the form designer or at run time. The only tricky part is that controls marked as Private in ParentForm will be visible on ChildForm but will not be accessible through code. This seems odd at first blush, but it makes sense when you remember that only protected and public members of a base class are visible to its derived classes.
If you use the Visual Studio form designer, you'll notice that inherited private controls are indicated by a rectangular selection cursor (see Figure A) and that you can inspect their properties but not modify them in the properties inspector.
|A base and inherited form with private, public, and protected controls|
Since I brought up the topic of the form designer, I ought to mention some peculiarities inherent in using it with visual inheritance:
- The designer requires that the base form or control be in a previously compiled and referenced assembly before you can select it as a base class. This has to do with how the designer renders forms for you in the design window and isn't a requirement if you aren't using it.
- Any changes made to the base form or control will not be reflected in the derived form's design window until the base form's assembly is rebuilt. The Visual Studio task list will politely remind you to do so if you modify a base form's design.
- To change the scope modifier on a control or form element, you can either manually change the declaration for that element in the code (variable declarations are outside the Windows Form Designer Generated Code block, so you may modify them without penalty) or change it using the designer's properties inspector via its Modifiers property.
Flexible and efficient form design
One of the most obvious uses for visual inheritance is to build form templates that contain common GUI elements that must appear on all forms in an application. For example, if you have a requirement that all forms display the company logo and have a help button or a common menu structure, just create a base form that includes these elements and derive any new form from it.
Another use may be less obvious, but it has much more potential. You can use inheritance to alter a form's behavior or appearance based on who's using it or what it's being used for.
A visual tour
Take a simple data entry/maintenance form, such as the order entry form in Figure B.
|The Magic Widget Company's order-entry application|
Suppose that you have users who need to view this data but who do not need the ability to edit it. We'll call them Browsers. Now further suppose, and this shouldn't be much of a leap, that you have other users who will actually need to enter and edit data using a similar form. We'll call these users Editors.
Ordinarily, you'd get functionality like this by writing some code that determines what class of user is viewing the data and then locks or hides the editing controls for a Browser and unlocks or shows the editing controls for an Editor. Adding a new class of user, say a Biller, who only needs to mark the orders as billed and paid, would require you to create a few new controls on your form and add a new branch to your code to handle locking and unlocking the appropriate controls for each user role. Then, you'd likely need to test the form once for each role to make sure you didn't break Browser's or Editor's behaviors by adding behavior for Biller.
Using visual inheritance, however, you could create a single base form containing all your common controls, along with common code for things like data access. You could then derive new forms from your base form that provide the functionality appropriate for each of your user classes—one each for the Browser, Editor, and Biller users from my example above. Since all three of these forms share the same base class, your code can treat any of them as an instance of your base form's class, downcasting only when necessary.
The Visual Studio.NET project includes three forms similar to the one shown in Figure B above:
- TemplateForm forms the base class that the others derive from and contains code to access data from a data source (a fixed-length-field text file in this case).
- BrowserForm derives from TemplateForm and is used by browser-class users who only need to view data on orders.
- EditorForm also derives from TemplateForm, but it provides full editing functionality for editor-class users.
I didn't implement a form for biller-class users in this example, but it could be easily done. Consider that a test for you, to see if you have a good grasp of this process.
The value of visual inheritance
Do you see some interesting ways, beyond those mentioned in this article, that visual inheritance could make your life simpler? Send us an e-mail with your ideas and suggestions or post a comment below.