Visual Inheritance
Visual inheritance is a fancy name for form inheritance, which is similar to the custom control pattern you use to create specialized .NET controls. Depending on how you use visual inheritance, you can really accomplish two things:
Use a common form template (visual appearance) for several different windows. This might be useful to create a wizard or standardized About window.
Use form functionality in several different windows. This allows you to create a framework that you might use for different types of view windows in a MDI application. Every window will have its own look, but it might reuse some of the same buttons to close the window or open a file.
And, as with any type of inheritance, visual inheritance gives you many different ways to customize how the descendent class can use, extend, or override the inherited class.
To create a simple example of form inheritance, you might create a wizard form like the one shown in Figure 5-30. It uses a blank header area for title text, a large surface area for additional content, and a Next button at the bottom. In this example (found in the code for this chapter under the project name VisualInheritance), the base form is named Ancestor.

Figure 5-30: An ancestor form for a wizard
To create an inherited form that uses this form, you first need to compile the project (unless the form is already stored in a separate assembly from your project). Then, right-click the project item in the Solution Explorer and choose Add → Inherited Form. You'll be prompted to choose a new form name, and select the form you want to derive from (see Figure 5-31).

Figure 5-31: Inheriting from a form
Of course, you don't actually need to use the wizard to create an inherited form. All you really need to do is create a Form class, and change the standard class declaration (which inherits from the System.Windows.Forms class) to inherit from your custom class. Make sure you use a fully qualified name that includes both the project namespace (in this case, VisualInheritance) and the form name.
public class Descendent : Inherits VisualInheritance.Ancestor
You'll notice that the inherited form contains all the controls that you defined in the original form, but it doesn't allow you to move them, change their properties, or add event handlers. You can, however, add new controls, write their event handlers, and change the size (or any other property) for your descendant form. In the basic example, this doesn't allow the flexibility you need. For example, the user needs to have some way to configure the label control in the title area and override the function of the Next and Previous buttons. Fortunately, this is all easy if you understand a few basics about inheritance.
Tip
Whenever you change the ancestor form, you must recompile the project before you see the appropriate changes in the descendant form. Just right-click the project in the Solution Explorer and choose Build to create the assembly without launching it.
Making an Ancestor Control Available
By default, every control on the original ancestor form is declared with the Friend modifier. This keyword allows access to other forms in the same project, but it doesn't allow any access to your derived form. To change this state of affairs, simply modify the controls you want to configure to use the Protected modifier instead. You can change the declaration by looking through the form code, or you can use the Properties window, and look for the special Modifiers property.
Once you've made this change, you'll find that you can configure any aspect of the inherited controls, including their appearance and position. The values used in the base form become the default values in the derived form, but any changes you make are recorded in the derived form's designer code and applied automatically when the form is created.
Adding an Ancestor Property
In our wizard example, creating protected-level controls may not be the best approach. Quite simply, it allows too much freedom to change the original layout. Take the header text, for example. The creator of the derived form should be able to enter custom text into the control, but other details (like its font, color, and position) shouldn't be modifiable, as they risk compromising the standardized layout you've established.
To code a better solution, you could create a special property in the base form. The client could then use this property to set the header text, without being allowed any greater degree of control.
public string HeaderText
{
get
{
return lblHeader.Text;
}
set
{
lblHeader.Text = value;
}
}
In your ancestor form, this property is available through code—and it also appears as value the user can set in the Properties window (see Figure 5-32). In fact, you can add other attributes to this property that configure the description it shows and the category it will appear in, but that topic is explored in Chapter 10.

Figure 5-32: A custom property
Overriding an Event Handler
Your base form might also contain event-handling logic. If this logic is generic (for example, it simply closes the form) it is suitable for all descendants. In the case of your Previous and Next buttons, there clearly is no generic code that can be written. Instead, the descendant needs to override the event handling code.
To accomplish this, you need to declare that the event handler can be overridden by marking it virtual in your ancestor form:
protected virtual void cmdNext_Click(object sender, System.EventArgs e)
{
MessageBox.Show("Ancestor form event handler.")
}
You can then override the routine in your descendant form:
protected override void cmdNext_Click(object sender, System.EventArgs e)
{
MessageBox.Show("Descendant form event handler.")
}
Note that you do not connect this code by adding an event handler. That's because the original routine (the one you are overriding) is already connected to the event. Another way to get around this situation is just to mark the control in the base form as protected. In this case, you don't need to include an ancestor event handler; instead, the derived form can write event-handling code directly. The side effect is that you lose your protection, and any other aspect of the control can also be modified in the derived form.
In some cases, you might want to execute both the extra code in the descendant form, and the original code. You can accomplish this by using the base reference. The code that follows, for example, results in the display of two message boxes, one from the ancestor form, followed by one from the derived form.
protected override void cmdNext_Click(object sender, System.EventArgs e)
{
// Call the original version.
base.cmdNext_Click(sender, e);
MessageBox.Show("Descendant form event handler.");
}
Finally, in some cases you might want to force an event handler to be overriden. For example, in our example a wizard form can't be considered complete unless it has the necessary event handling logic behind added to its next button. However, it's impossible to code this logic at the ancestor level. To force the derived class to override this event handler (as a precautionary measure), you can declare the event handler with the abstract qualifier. In this case, you can't add a method body.
protected abstract void cmdNext_Click(object sender, System.EventArgs e);
For this to work, the ancestor form class must also be declared abstract.
public abstract class Ancestor : System.Windows.Forms.Form
Be warned that this pattern can confuse the Visual Studio .NET IDE, and could even cause it to stop displaying your derived forms (although the code will work without a hitch). The best approach is to create a separate DLL assembly for your base forms, and add this as a reference to any client applications that want to inherit from these classes.
As you master visual inheritance, you might want to expand the inheritance technique to include your custom controls. Chapter 7 is dedicated to this approach.