-4

我正在尝试更改自定义 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 期间,只能执行绘制 Visual 内容的绘制操作。

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

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

4

2 回答 2

0

您也许可以通过相应地检测它来防止在设计时呈现

因此,如果我稍微修改您的代码,它在设计器中的表现也应该很好

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");
    }
}
于 2014-05-26T05:28:23.607 回答
0

如果在渲染周期中修改视觉对象本身会引发异常,并且设计人员在渲染周期中获取视觉对象而无需事先进行排列处理。

但是,在渲染期间修改 a 的内容是完全合法的DrawingGroup,即使它DrawingGroup是 a 的成员Visual

只需在构造函数中添加一次DrawingGroupDrawingVisual

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");
    }
}
于 2014-06-12T21:37:34.800 回答