在WPF中,如何在实际渲染之前获取控件的渲染大小?

时间:2011-04-13 16:01:03

标签: wpf layout resize rendering render

我在Decorator子类中进行自定义渲染。我们的渲染需要创建复杂的几何体,只有在实际渲染的尺寸发生变化时才会重新创建。因此,我已将几何创建移动到其自己的名为UpdateGeometry的函数中,该函数创建,然后冻结几何体以在OnRender中使用。只需响应ActualWidthActualHeight中的更改,即可调用此新功能。

更好的是,看起来我们应该能够简单地覆盖OnRenderSizeChanged,根据文档说明......

  

“在派生类中重写时,   参与渲染操作   由布局指示   系统。之后调用此方法   布局更新,以及渲染之前 ,   如果元素的RenderSize有   由于布局更新而更改。“

但是,无论我使用覆盖还是收听ActualWidthActualHeight的属性更改通知,我的记录始终会首先显示OnRender!嗯......什么?

为了确保它不是我在我的代码中所做的事情,我创建了一个简单的测试装饰器子类并在那里添加了日志记录,包括进入和退出覆盖。这是全班......

using System;
using System.Windows.Controls;

public class TestControl : Decorator
{

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
    {
        Console.WriteLine("OnRender Entered");

        base.OnRender(drawingContext);

        Console.WriteLine("OnRender Exited");
    }

    protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo)
    {
        Console.WriteLine("OnRenderSizeChanged Entered");

        base.OnRenderSizeChanged(sizeInfo);

        Console.WriteLine("OnRenderSizeChanged Exited");
    }

}

正如我所担心的......这是输出......

OnRender Entered
OnRender Exited
OnRenderSizeChanged Entered
OnRenderSizeChanged Exited

那我在这里错过了什么?

更重要的是,如何在布局子系统完成其工作后获取ActualWidthActualHeight值,但是在渲染控件之前,我可以在{}中需要之前创建几何体{1}}覆盖?

我的最新实施会覆盖OnRender,因为其中传递的值的大小包含ArrangeOverrideActualWidth 应该 在核心布局系统考虑ActualHeightHorizontalAlignment后,其值为“拉伸”,最小值和最大值等,但它们实际上取决于从该覆盖返回的值,所以它比那复杂一点。

无论哪种方式,我仍然想知道为什么VerticalAlignment调用不应该发生。想法?

标记

1 个答案:

答案 0 :(得分:4)

通常,您应该能够从ArrangeOverride获得正确的尺寸。这不包括保证金等内容,但可能不应该考虑到这一点。您可以使用作为参数传递的大小作为“渲染”大小,也可以使用base.ArrangeOverride调用的返回值。

编辑:

在最终调用OnArrangeOverride之后,从Arrange方法调用OnRender方法。另一方面,OnRenderSizeChanged是从UpdateLayout调用的,有效地调度它以便对可视树的给定部分一次性执行。这就是在OnRender之后调用OnRenderSizeChanged的原因。

文档可能会将“渲染”称为实际呈现给屏幕,而不是在调用OnRender时。 WPF可以缓存给定元素的呈现指令,并在需要时执行它们。因此OnRender在OnRenderSizeChanged之前调用的事实并不意味着当时它的实际渲染指令已提交到屏幕。

您可以修改OnRenderSizeChanged以强制使用以下方法再次调用OnRender:

protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo)
{
    Console.WriteLine("OnRenderSizeChanged Entered");

    base.OnRenderSizeChanged(sizeInfo);
    this.InvalidateVisual();

    Console.WriteLine("OnRenderSizeChanged Exited");
}

如果RenderSize为“0,0”,您可能还想跳过OnRender代码。