Testing Custom Controls
Testing custom controls can sometimes be a little awkward. Visual Studio .NET provides several options:
You can add test forms directly to your control class projects and remove them when they are no longer needed (or just set the Build Action to None instead of Compile, so that they are retained but not added to the compiled DLL).
You can create a solution with two projects: one that tests the control, and one that uses the control. However, you may find that you need to close the solution and reopen it to see changes to the control's design-time behavior.
You can open two instances of Visual Studio .NET, one with the control project, and one with the control test project. Once again, you may need to close and reopen the client project to see changes in a control's design-time behavior.
You can use the specialized PropertyGrid control examined in this section.
Even if you don't follow one of these specialized approaches, if an error occurs in your custom control code and the .vb source file is available, Visual Studio .NET automatically loads the file and enters break mode, pausing execution on the offending line.
Debugging Design-Time Support
If you test your custom control in a project with the control source code, you are able to set breakpoints and use other debugging tricks. However, these breakpoints are ignored at design time, and only have an effect while the control is running "live."
This limitation can hamper your testing to a certain extent. Developing good design-time support for your control requires a different set of considerations than creating its basic functionality. One solution to this problem is to debug the IDE itself. To accomplish this, add your control to the toolbox, and then configure your custom control project to start Visual Studio .NET when you run it (see Figure 8-8). You can now set breakpoints in your control code or custom designer code that are triggered as the control is manipulated in the IDE.

Figure 8-8: Debugging design-time support
Testing for Design Mode
You may also notice some quirky design-time behavior that doesn't occur if the control is added programmatically. For example, if you add the DirectoryBrowser at design time, you'll discover some quirky behavior.
At first, it seems straightforward enough-once you set the Drive property, the corresponding directory tree appears. You can even expand nodes and browse the directory structure at design time, as shown in Figure 8-9.

Figure 8-9: The DirectoryTree at design time
However, when you start your program, a second set of identical directory nodes appears. The problem is that the nodes you create at design time are automatically serialized to the form's designer code. At runtime, the control is re-created, the directory nodes are rebuilt when the drive property is set, and then the serialized nodes are added.
There are several ways you can resolve this problem. First, you could change the order of the form designer lines so that the Drive property is configured after the serialized nodes are added (setting the Drive property automatically clears the current list of nodes). Alternatively, you could create a custom designer, as you do later in this chapter. The simplest approach, however, is just to configure DirectoryTree control so that it doesn't provide its directory Node display at design-time. You can do this by explicitly checking what mode the control is in before refreshing the display.
public char Drive
{
get
{
return drive;
}
set
{
drive = value;
if (!this.DesignMode)
{
RefreshDisplay();
}
}
}
The PropertyGrid Control
Another way to test your control is using .NET's specialized PropertyGrid control. This control is actually an exact replica of the Properties window contained in the Visual Studio .NET environment. You can add this control to a form, and use it to run your custom control through its paces by modifying any of its properties. This is a good practice to get into-if you try to set invalid property values, you'll probably discover that your control isn't as successful as you expect at rejecting them. By default, the PropertyGrid control doesn't appear in the toolbox. To add it, you need to choose Customize Toolbox and find it in the list. The PropertyGrid provides properties that allow you to format its appearance and configure its display. The most important property, however, is SelectedObject. When you set the SelectedObject to an instance of a control, the grid automatically fills with a list of all the available properties. When you change a property in the grid, it is applied to the control immediately. Figure 8-10 shows a test project that combines an instance of the DirectoryTree control with a PropertyGrid. This example is included with online samples for this chapter as the project named DirectoryTreeClient.

Figure 8-10: The PropertyGrid control
Tip
Interestingly, you can use the PropertyGrid control with any object, regardless of whether it is a control, component, or simple class. The PropertyGrid allows you to modify any public property exposed by the class.