Stackpanel:高度vs ActualHeight vs ExtentHeight vs ViewportHeight vs DesiredSize vs RenderSize

时间:2011-06-19 14:48:42

标签: wpf layout height scaling stackpanel

2 个答案:

答案 0 :(得分:14)

如您所知StackPanel是[Panel]对象。每个小组通过两种方法与其子女沟通,以确定最终的大小和位置。 第一种方法是MeasureOverride,第二种方法是ArrangeOverride

MeasureOveride在给定数量的可用空间的情况下询问每个孩子所需的大小。 测量完成后ArrangeOverride安排孩子们。

让我们创建一个stackpanel:

public class AnotherStackPanel : Panel
{
    public static readonly DependencyProperty OrientationProperty =
        DependencyProperty.Register(“Orientation”, typeof(Orientation),
        typeof(SimpleStackPanel), new FrameworkPropertyMetadata(
        Orientation.Vertical, FrameworkPropertyMetadataOptions.AffectsMeasure));

    public Orientation Orientation
    {
        get { return (Orientation)GetValue(OrientationProperty); }
        set { SetValue(OrientationProperty, value); }
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        Size desiredSize = new Size();

        if (Orientation == Orientation.Vertical)
            availableSize.Height = Double.PositiveInfinity;
        else
            availableSize.Width = Double.PositiveInfinity;
        foreach (UIElement child in this.Children)
        {
            if (child != null)
            {
                child.Measure(availableSize);

                if (Orientation == Orientation.Vertical)
                {
                    desiredSize.Width = Math.Max(desiredSize.Width,
                    child.DesiredSize.Width);
                    desiredSize.Height += child.DesiredSize.Height;
                }
                else
                {
                    desiredSize.Height = Math.Max(desiredSize.Height,
                    child.DesiredSize.Height);
                    desiredSize.Width += child.DesiredSize.Width;
                }
            }
        }
        return desiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        double offset = 0;
        foreach (UIElement child in this.Children)
        {
            if (child != null)
            {
                if (Orientation == Orientation.Vertical)
                {               
                    child.Arrange(new Rect(0, offset, finalSize.Width,
                    child.DesiredSize.Height));                 
                    offset += child.DesiredSize.Height;
                }
                else
                {                   
                    child.Arrange(new Rect(offset, 0, child.DesiredSize.Width,
                    finalSize.Height));
                    offset += child.DesiredSize.Width;
                }
            }
        }
        return finalSize;
    }
}
  • DesiredSize(大小 MeasureOverride)返回的是总和 儿童大小的方向 StackPanel的大小最大 孩子在另一个方向。

  • RenderSize代表决赛 布局后StackPanel的大小 已经完成了。

  • ActualHeight与...完全相同 RenderSize.Height

要依赖这些属性,您应该只在LayoutUpdated事件的事件处理程序中访问它们。

答案 1 :(得分:3)

以上答案是正确的,但RenderSize和ActualHeight可以暂时具有不同的值。 RenderSize在OnRender之前设置,而一旦WPF完成布局并为该控件渲染处理,ActualHeight就会被设置。最后,LayoutUpdated会被提升。

因此,RenderSize可以在OnRender中使用,但ActualHeight仍将具有布局开始之前的旧值。

序列如下所示:

MeasureOverride() => sets DesiredSize
ArrangeOverride() => sets RenderSize
OnRender()

WPF可能会多次执行此序列(递归)。一切都解决后,执行以下操作:

ActualHeight = RenderSize.Height

在第一次布局完成后,可以随时(!)访问ActualHeight,除了在测量,排列和渲染的布局过程中。 WPF确保在布局处理运行之前完成任何代码。