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.