I'm trying to change a custom WPF element to use a visual tree, so that background layers can be changed without needing to throw away the whole retained render. At the same time, a layer might be affected by more than one property, so I'd like to redo the render lazily, in case multiple properties get changed in a single screen update cycle. Here's what I did.
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
private readonly DrawingVisual textLayer = new DrawingVisual();
bool textLayerReady;
protected override Visual GetVisualChild(int index)
{
switch (index)
{
case 0:
if (!textLayerReady)
{
using (var textContext = textLayer.RenderOpen())
RenderTextLayer(textContext);
}
return textLayer;
default:
throw new ArgumentOutOfRangeException("index");
}
}
It seems to run correctly, but in the designer I get:
InvalidOperationException: Cannot call this API during the OnRender callback. During OnRender, only drawing operations that draw the content of the Visual can be performed.
I suppose that at runtime the layout process is calling GetVisualChild
prior to the actual render, and the design canvas operates differently?
Is this a reasonable thing to attempt? How should I trigger the render of child drawingvisuals in order to ensure it happens at a legal time?
Visuals themselves throw exceptions if modified during the render cycle, and the designers fetch visuals during the render cycle without going through the arrange processing beforehand.
However, it's perfectly legal to modify the contents of a
DrawingGroup
during render, even if thatDrawingGroup
is a member of aVisual
.One merely needs to add the
DrawingGroup
to theDrawingVisual
once in the constructor:Then later, one can replace the content lazily when it's actually needed for rendering, while still keeping the advantages of retained mode (not reconstructing the "vector graphics instruction lists" as WPF terms it, for unchanged layers).