Introduction
WpfVisualVisualizer
"Glimps" enables you to preview a WPF control within the Visual Studio debugger while stepping through the application code, making it easier to debug complex WPF user interfaces.
Josh Smith has already written an excellent debugger visualizer, that allows you to inspect properties of WPF elements, which can be found here.
Background
In WPF applications, there are often lots and lots of visuals. When you're debugging, it is often hard to know which visual element is referenced by a certain variable.
WpfVisualVisualizer
renders a Visual or Control to a small image that you can preview in the debugger. This works with any kind of Visual, even Videos or 3D, once it is initialized and loaded.
Deploying Glimpse
Please see Josh Smith's article on how to deploy a Visual Studio debugger visualizer here. It is a great read, anyway.
How to Use It
When Glimps is installed, you can select it from the tooltip if you hover over a WPF visual in the debugger, as seen in the screenshot at the top of the page.
Limitations
UIElements
and FrameworkElements
must be initialized and loaded before they can be displayed. As a result, when you put a breakpoint in the constructor, you won't see anything.
How it Works
A debugger visualizer consists of two parts:
The first part (IVisualizerObjectProvider
) runs within the process of your application. This part is responsible for gathering and serializing the required information that will be displayed in Visual Studio.
The second part (DialogDebuggerVisualizer
) runs within the Visual Studio debugger and is responsible for displaying the information. This is the actual Visualizer.
In order to display a WPF visual as a thumbnail image in Visual Studio, it must be rendered to bitmap in the context of the application, then converted to a GDI image. This will be sent over the wire to the visualizer, which is a simple WinForms dialog.
The DebuggerVisualizer
requests the data it will visualize by calling the GetData
method on the ObjectProvider
. GetData
returns a Stream
which contains the serialized data.
The visualizer and object provider are tightly coupled, so the visualizer knows that the Stream
contains an image and will display it in a PictureBox
:
protected override void Show(IDialogVisualizerService windowService,
IVisualizerObjectProvider objectProvider)
{
Stream s = objectProvider.GetData();
Image image = Image.FromStream(s);
Form form = new Form();
form.Text = "WPF Visual";
form.ClientSize = new DrawingSize
(WpfVisualObjectSource.MaxSize.Width, image.Height);
form.FormBorderStyle = FormBorderStyle.FixedToolWindow;
if (image != null)
{
PictureBox pictureBox = new PictureBox();
pictureBox.Image = image;
pictureBox.Parent = form;
pictureBox.Dock = DockStyle.Fill;
form.Controls.Add(pictureBox);
}
windowService.ShowDialog(form);
}
On the ObjectProvider
side, the targeted WPF visual needs to be rendered to a BitmapSource
and then converted to a GDI image that we can display in WinForms:
public override void GetData(object target, Stream outgoingData)
{
Image img = null;
if (target is BitmapSource)
{
img = BitmapSourceToGdiImage((BitmapSource)target);
}
if (target is FrameworkElement)
{
FrameworkElement fe = (FrameworkElement)target;
if (!fe.IsLoaded) img = CreateEmptyBitmap();
}
if (img==null && target is Visual)
{
BitmapSource bmpSource = CreateBitmapSource((Visual)target);
img = BitmapSourceToGdiImage(bmpSource);
}
if (img == null) img = new Bitmap(0, 0);
img.Save(outgoingData, ImageFormat.Bmp);
img.Dispose();
}
History
- 11/15/2007 - Uploaded first version
- 11/16/2007 - Josh Smith added Glimps to Woodstock for WPF and also made some improvements in the code. He was kind enough to add me as an author.