In Depth Banner
Skip Navigation LinksWelcome > In Depth articles > Debugging Controls

Debugging Windows Forms Controls

.NET has fundamentally changed the way we write objects because reuse is something built into the very foundations of the framework. Where we would have built a class or a widget in C++ a few years ago and re-written almost exactly the same code on the next project we can now re-use and recycle objects from their executable assemblies, derive from them, use them in VB or C++ even when they're written in C# and use them at design time in the Visual Studio IDE. This encourages developers to consider creating a component or control as the primary and preferred method rather than only adding such cool features after the tool has gone through several iterations.

Thinking of creating a component or control first rather than after all the real code is in place adds an extra layer of indirection to your build and test process. When the code was stand-alone you could write a little test harness right there and then run it to see what happens. When functionality is in an object derived from Component or Control, you have to test it at design time and runtime to verify that the behaviour is consistent and sensible.

Perhaps the first time you create any sort of control using Visual Studio it will be a UserControl based object. These are simple to use, can be populated with other controls dragged from the toolbox and will miraculously turn up in the toolbox as soon as you build the project, even when it's not all finished, for use on your forms and such. Objects based on UserControl can be ideal if all you want to do is assemble a few controls into a reusable block, drop the block onto a form and hit the "Go" button. You cannot however create a UserControl or indeed any other component and test it at design time with this method. As the UserControl implementations you create become more complex, the more likely a puzzling and seemingly impossible to find error is. A control that crashes at design time is a major problem because all you see is the dreaded red X and the stack trace.

Read on now to discover the right way to go about debugging complex controls at run time and design time.

Creating the control

Start a new project from the main Visual Studio menu and in the project wizard select a Windows Control Library. Call it "DebugControl" and press OK to accept the selections.

Because Visual Studio's default name options are a bit odd, do a global search and replace on DebugControl and replace it with WellFormed. This will be the namespace. Similarly do a search and replace for UserControl1 and replace it with DebugControl.

Drag a ListBox and a PictureBox onto the control to create something like that seen in Figure 1.

Figure 1: The assembled control.

This control is going to provide the ability to browse for an image file with a preview at runtime. At design time, the browsing abilities of the control must be turned off and the preview display a sensible default.

Biulding and running for the first time.

Even thought there is no real functionality in this control. Now is a good time to build and run it so that future debugging cycles can be made easier. To debug a control it must be run in a container of some sort such as the Visual Studio IDE or a form. To accomplish this you have to set up the debugging properties of the solution. Right click the solution and select Properties.

This brings up the dialog shown in figure 2. In the left hand pane, select Configuration properties, Debugging

 

Figure 2. Setting up the debug mode

The debug mode property should be set to Program and the  apply button clicked once. This enables you to edit the Start Application property by typing in a path or clicking on the browse button which is made available. Browse to the Visual Studio IDE executable devenv.exe which will probably be found in the "C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE" directory or in a similar one if you've installed the IDE to a different place. Figure 3 shows this.

Figure 3: Selecting the development environment.

Pressing the Run button or the F5 key now will run a second copy of the development environment that is attached to the debugger of your original copy of Visual Studio. Now you're ready to create the test harness and debug the design time abilities.

Create the test program.

Usually for a control, you will test in a form so a new application with a blank form will be created in the normal way as seen in Figure 4.

Figure 4: Creating the test application with the Application Wizard.

The toolbox needs to contain the control that's being debugged so a right click on the toolbox brings up a menu from which you can select Add / Remove Items as seen in Figures 5 and 6.

Figure 5: Adding the control to the toolbox (part 1)

Figure 6: Browse to select your control DLL.

With the control in place on the toolbox, you can drag it to a form and voila... the control is running in design time mode.

Making life easy.

Next time around, it would be great to have this test program run automatically for you whenever you press the F5 key. This is accomplished by a simple trick.

In the second instance of the IDE, click File, Open and find the Solution file for the current project. In this case it will be TestDebugControl.sln. Dont open it but right click on the solution file and create a shortcut to it. Next, right click on the shortcut and select Properties. The property target edit box contains the path to the solution file. Select it and copy the whole string to the clipboard. Now close the file open box with the Cancel button, you don't really need to open a file.

Close the second copy of the IDE completely and return to the first. Right click the solution again and go back to the debugging configuration where you will paste the path on the clipboard into the Command Line Arguments box as seen in figure 7.

Figure 7: Command line arguments ensure the right debug test project

In the future, whatever the settings of your Visual Studio startup options, you can be sure that the correct test project is loaded for your control DLL.

Code yourself silly.

For brevity and to stay on the subject of debugging, the code for the complete debug control is provided here already to roll. Figure 8 shows the control running in a form. Take a few moments to study the listing and familiarize yourself with the source.

Figure 8: The debug control in working order.

Debugging at design time.

Because the second instance of the IDE runs under the debugger of the first, you can exercise the control in the designer, place breakpoints and trap errors with ease. Trace statements created by the control at design time are seen by the trace listener in the first copy of the IDE so if you use them to help in the debugging process, you'll see them in the output window as they happen. Figure 9 shows the two instances of Visual Studio running, the control in the designer of the second instance and the output from the Trace statements shown in the first instance.

Figure 9: Trace statements caught from the design time instance of the control.

Now, you can set breakpoints in the control to see what is going on at design time. Controls have a boolean property DesignMode which is set to true whenever the control is active in the designer. You can use this property to limit behaviour of a control that does a lot of processing or hogs resources at design time.

To demonstrate this, in the first instance of Visual Studio, set a breakpoint in the UpdateListbox method as shown in figure 10 and then, in the designer of the second instance of Visual Studio, change the Path property of the DebugControl. The execution will stop in the first instance of VS and you can step through the code to see that the control is in design mode and the directories are not actually scanned.

Figure 10: A breakpoint in the control.

Runtime debugging.

The Visual Studio team have really got their act together on this one. Debugging at runtime is so easy in comparison to what was available with Visual Studio 6 and C++.

To debug the code in your DLL, you only need to browse to the file, open it, set a breakpoint and even though the debug target is in fact the executable, the execution will stop at the right place and you can step over the code and examine the variables and properties. Trace statements are also captured by the debugger and shown in the output window.

Summary.

In this article, you've seen how to set up the debug environment to allow quick and efficient debugging of controls. The debug configuration was adjusted to run a second instance of the Visual Studio IDE (devenv.exe) and then later, reconfigured again to ensure that the correct debug test project was loaded every time the control debug cycle started. You've also seen how to issue trace statements from the design time of the control which were caught in the debugger and how to stop execution at design time to verify design time behaviour.

Source code example can be found in following locations.

Return to the main index.

 

Copyright © Bob Powell 2003-2009. All rights reserved