Wednesday, April 04, 2007 3:50 AM
bart
Writing custom Visual Studio 2005 Debugger Visualizers
A little-known feature in Visual Studio 2005 is the possibility to create a custom debugger visualizer. In this post, we'll take a closer look at this feature. A debugger visualizer allows you to associate a custom control or Windows Form with an object type definition in order to visualize that particular type in a user-friendly fashion while debugging in Visual Studio 2005. Assume the following type definition:
public class Bar
{
private string name;
private int age;
private string secret = "Foo";
public Bar(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
set { name = value; }
}
public int Age
{
get { return age; }
set { age = value; }
}
public string Secret
{
get { return secret; }
set { secret = value; }
}
}
Assume a simple application that does the following:
1 public partial class Form1 : Form
2 {
3 public Form1()
4 {
5 InitializeComponent();
6 }
7
8 private void button1_Click(object sender, EventArgs e)
9 {
10 Bar b = new Bar("Bart De Smet", 24);
11 }
12 }
Set a breakpoint on line 11 and execute the application using the debugger. Normally you'll see something like this:
Observe the zoom glass icon displayed next to the strings name and secret. If you click the arrow at the right of it, you see this:
These three, the "Text Visualizer", "XML Visualizer" and "HTML Visualizer", are so-called debugger visualizers. What we want to do, is to create such a visualizer for our Bar type. In order to do so, add a new item to the project and choose for the Debugger Visualizer template type and call it BarVisualizer:
Change the code as follows:
public class BarVisualizer : DialogDebuggerVisualizer
{
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
Bar data = (Bar)objectProvider.GetObject();
windowService.ShowDialog(new BarVisualizerControl(data));
}
}
[DebuggerVisualizer(typeof(BarVisualizer), Description = "Bar Visualizer")]
[Serializable]
public class Bar
{
private string name;
private int age;
private string secret = "Foo";
public Bar(string name, int age)
{
this.name = name;
this.age = age;
}
[Browsable(true), Category("Author"), Description("Name of the author")]
public string Name
{
get { return name; }
set { name = value; }
}
[Browsable(true), Category("Author"), Description("Age of the author")]
public int Age
{
get { return age; }
set { age = value; }
}
[Browsable(false)]
public string Secret
{
get { return secret; }
set { secret = value; }
}
}
For the Bar type, observe we've added a few attributes from System.ComponentModel to make these display properly in a PropertyGrid control, as shown below. More specifically, these attributes give the properties a friendly name, as well as a category. The Secret property won't be displayed because we set it's browsable attribute to false.
The most important portion however, is the DebuggerVisualizer attribute on top of the class, telling the VS2005 debugger which type to load as the debugger visualizer for the type. Our visualizer, BarVisualizer, creates a new BarVisualizerControl instance to show the object. It's defined like this:
This user control simply contains a (.NET 2.0) PropertyGrid object, called propertyGrid1. The code behind contains the following:
public partial class BarVisualizerControl : UserControl
{
public BarVisualizerControl(Bar bar)
{
InitializeComponent();
propertyGrid1.SelectedObject = bar;
}
}
Congratulations, your first debugger visualizer is ready! Run the application in the debugger with the breakpoint set as mentioned earlier and observe the visualizer being available in the VS2005 debugger:
When you click the visualization icon, the following appears:
Nice, isn't it? Of course, you could create much more complicated debugger visualizers that host a bunch of functionality. Just to give you an idea, think of a visualizer for a database connection kind of class that allows to test the connection using the settings available, or to open up a query creationtool to run against the connectionto check whether or not authorization to certain tables or sprocs works correctly for the given connection settings.
Furthermore, you can also attach a visualizer to a type you don't maintain yourself, by using the [assembly: DebuggerVisualizer(...)] attribute inside a class library project. Compile the project and copy the DLL file to the %programfiles%\Microsoft Visual Studio 8\Common7\Packages\Debugger\Visualizers folder. An example is shown below:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.VisualStudio.DebuggerVisualizers;
[assembly: DebuggerVisualizer(typeof(MyVisualizers.StringVisualizer), typeof(VisualizerObjectSource), Target = typeof(string), Description = "My String Visualizer")]
namespace MyVisualizers
{
public class StringVisualizer : DialogDebuggerVisualizer
{
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
string data = (string)objectProvider.GetObject();
using (Form f = new Form())
{
f.Text = data;
windowService.ShowDialog(f);
}
}
}
}
Notice you can also change the object through the visualizer; have a look at the IVisualizerObjectProvider's ReplaceObject and TransferObject methods, as well as the IsObjectReplaceable read-only property.
Have fun!
Del.icio.us |
Digg It |
Technorati |
Blinklist |
Furl |
reddit |
DotNetKicks
Filed under: Visual Studio 2005