绘图视觉的延迟渲染

本文关键字:延迟 视觉 绘图 | 更新日期: 2023-09-27 18:04:58

我正在尝试更改自定义WPF元素以使用视觉树,以便可以更改背景层而无需丢弃整个保留的渲染。同时,一个图层可能会受到多个属性的影响,所以我想要延迟重做渲染,以防多个属性在一个屏幕更新周期中被更改。我是这么做的。

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");
    }
}

它似乎运行正确,但在设计器中我得到:

InvalidOperationException:在OnRender回调期间不能调用此API。在OnRender期间,只能执行绘制可视化内容的绘图操作。

我想,在运行时的布局过程是调用GetVisualChild之前的实际渲染,和设计画布操作不同?

这是一个合理的尝试吗?我应该如何触发渲染的儿童绘画视觉,以确保它发生在一个合法的时间?

绘图视觉的延迟渲染

您可以在设计时通过相应地检测来阻止渲染

所以如果我稍微修改一下你的代码它在设计器中也会正常运行

private readonly DrawingVisual textLayer = new DrawingVisual();
bool textLayerReady;
protected override Visual GetVisualChild(int index)
{
    if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
    {
        return; //do not perform custom logic during design time
    }
    switch (index)
    {
        case 0:
            if (!textLayerReady)
            {
                using (var textContext = textLayer.RenderOpen())
                    RenderTextLayer(textContext);
            }
            return textLayer;
        default:
            throw new ArgumentOutOfRangeException("index");
    }
}

如果在渲染周期中修改视觉效果,则会抛出异常,并且设计人员在渲染周期中获取视觉效果,而无需事先进行安排处理。

然而,在渲染期间修改DrawingGroup的内容是完全合法的,即使DrawingGroupVisual的成员。

只需要在构造函数中将DrawingGroup添加到DrawingVisual一次:

DrawingGroup textLayer = new DrawingGroup();
DrawingVisual textVisual = new DrawingVisual();
using (DrawingContext textContext = textVisual.RenderOpen())
    textContext.DrawDrawing(textLayer);

然后,当渲染实际需要时,可以惰性地替换内容,同时仍然保持保留模式的优点(不重建WPF所说的"矢量图形指令列表",对于未更改的图层)。

protected override Visual GetVisualChild(int index)
{
    switch (index)
    {
        case 0:
            if (!textLayerReady)
            {
                using (var textContext = textLayer.Open())
                    RenderTextLayer(textContext);
            }
            return textVisual;
        default:
            throw new ArgumentOutOfRangeException("index");
    }
}