Search code examples
c#wpfvisual-studiodebuggervisualizer

Visualizer for WPF elements


Trying to create visualizers for some WPF elements including DrawingImage and UIElement etc. While creating a visualizer was trivial, my visualizers always throw exception that the target object types (DrawingImage and UIElement that is) are not marked as serializable.

Further reading revealed that I need to implement VisualizerObjectSource to provide custom serialization. This class is specified as one of the arguments in DebuggerVisualizer attribute. I followed these steps and now my custom serializer gets called, but I don't really know what to do in there. Here is the relevant function that gets called:

public override void GetData(object target, Stream outgoingData)
{
  var writer = new StreamWriter(outgoingData);
  writer.WriteLine(/*???*/);
  writer.Flush();
}

Don't understand exactly what it is expecting from me (a binary-serialized version of the UIElement?) and exactly how do I write a UIElement or a DrawingImage to the outgoing stream. Anyone has done this before?


Solution

  • Finally managed my way through it. It is much simpler than I had thought. For anyone else trying to find their way, here is how it works:

    Firstly, GetData() override (read the question) is to be managed by YOU. You have to decide what you want to send in to the visualizer. Send in enough information so that you're able to construct the object back in the Show() call.

    For WPF elements, serialization proved to be FAR simpler than what I was thinking. There are built-in XamlReader and XamlWriter classes that you can use to perform serialization/deserialization of WPF objects.

    Once you have reconstructed the object in Show(), it is simply a matter of showing it in a Form. Note that Visual Studio supports old-school Form and Control classes only (WinForms that is), not WPF Windows, but you can workaround this issue by placing an ElementHost in your form or control and then assigning reconstructed WPF object as the child of this ElementHost.

    You may want to add a ViewBox layer in between your ElementHost and the reconstructed object to fit it elegantly in the available space.

    I have uploaded the WPFVisualizers project on GitHub in case anyone is interested. Currently it contains two visualizers, for DrawingImage and UIElement types. Together these cover most of the visual elements of WPF world, but you're free to add more types in case you need some. The project contains VisualizerBase class that contains all the visualizer serialization/communication logic. This makes creating new WPF visualizers as simple as writing 1 line of code, like this:

    public class GeometryDrawingVisualizer : VisualizerBase<GeometryDrawing, GeometryDrawingControl>
    {
    }
    

    That's it. You have created a new visualizer for GeometryDrawing type. The second generic parameter (GeometryDrawingControl in the above example) is the WinForms Control (or Form if you wish) that will constitute the UI of your visualizer. Place an ElementHost in your control and then put in whatever your type needs to render.