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?
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 Window
s, 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.