As promised, an updated Visualizers How-To! My last how-to entry on Visualizers was targeted at the PDC release of Whidbey, as you may (or may not) remember. This time I don't feel the need to cringe at times as I describe the process. :0)
First, a high level overview of Visualizers. Visualizers allow for advanced, customized viewing of data while debugging. Today's data windows have their limitations; text-only, hierarchical, spatially constrained - not the best for viewing an image, for example. Visualizers allow you to create completely custom views using WinForms to best show the data within any managed object. Yes, unfortunately this feature will only available for the managed world.
A Visualizer is associated with a particular type. Whenever that type is seen by the debugger, a little magnifying glass will be shown next to its entry on datatips, the watch window, quickwatch, etc. Multiple Visualizers can be associated with one type, and a Visualizer can be associated with multiple types. A class derived from a class with Visualizers associated with it will inherit those associations, but Visualizers cannot be associated with interfaces (if you think this is an important scenario, let me know why).
Alright, let's get started.
First, create a new C# Class Library Project, perhaps named FirstVisualizer. To start off, you'll want to add a reference to meehost.dll; browse to this location in the Add References dialog: <VS Install Dir>\Common7\IDE\meehost.dll. Now we have access to all the interfaces and base classes we need to be able to communicate with Visual Studio.
Next open the auto-generated Class1.cs file. In the Solution Explorer tool window, right-click on it and rename it to "DebuggerSide.cs" - note that the IDE intelligently renames the class and constructor name in source as well. DebuggerSide is an appropriate name because this is the class which is loaded into Visual Studio to actually display the data. To make it easier to talk to the Visualizer interfaces, add 'using System.Diagnostics' to the top of the file. Next, type ': IDebugVisualizer' after 'class DebuggerSide' to implement the IDebugVisualizer interface defined in meehost.dll.
Now click on IDebugVisualizer - a small glyph will appear under the 'I' - a Smart Tag. Hover over it, click on the resulting larger icon, then select one of the options on the menu. The IDE will auto-generate the appropriate stubs to implement the very simple IDebugVisualizer interface.
The Show method you should now see in front of you is what is called when you click to see the visualizer while debugging. Let's add something useful to it. First, add System.Windows.Forms to your references - we need to show something graphical here. Optionally delete System.Data and System.XML, since we won't be using those (this can also be done with the using statements at the top - we only need System, System.Diagnostics, and System.Windows.Forms for this example). Now we can change 'throw new System.NotImplementedException();' to 'MessageBox.Show(objectProvider.GetObject().ToString());', which of course lacks necessary error-checking for possible nulls. I'm willing to take that risk for brevity. :0)
Now that we've created the visualizer. We need to tell Visual Studio that it is there, what to do with it. We've added a number of attributes for VS 2005 that will allow you to customize your debugging experience - DebuggerVisualizer is just one of them. It is defined in the BCL, and has a lot of constructors.
[assembly:DebuggerVisualizer( typeof(VisualizerObjectSource), typeof(FirstVisualizer.DebuggerSide), VisualizerUIType.Modal, Target = typeof(System.String), Description = "My First Visualizer")]
First, some bad news: unfortunately, invoking custom visualizers on strings from DataTips is broken in this build. Sorry. The good news is that your custom visualizer will work from any other data window.
When you invoke the visualizer, the MessageBox pops up with the contents of the string in it! Cool, eh? As with before, this visualizer is extremely trivial, and definitely pointless. It does, however, give you the basic method - you can easily build on top of these steps to create much more advanced, useful Visualizers.
I'll be writing another post soon addressing some more advanced topics with Visualizers, like performance. Using the above methods, you are sending the entire object around all the time. I'll also talk a little more in depth about the interfaces, like the IVisualizerObjectProvider passed in on the Show method.
Feeling a little lazy?