Stackpanel: 高度 vs 实际高度 vs 扩展高度 vs 可视区域高度 vs 期望大小 vs 渲染大小

26
我想知道我的StackPanel中所有项的高度。
以下是它们之间的区别:
  • Height - 获取或设置元素建议的高度。
  • ActualHeight - 获取此元素的呈现高度。(只读
  • ExtentHeight - 获取包含范围的垂直大小的值。(只读
  • ViewportHeight - 获取包含内容视口的垂直大小的值。(只读
  • DesiredSize - 获取此元素在布局过程的测量传递期间计算的大小。(只读
  • RenderSize - 获取(或设置,但请参见备注)此元素的最终呈现大小。

来自 MSDN:

高度
获取或设置元素的建议高度。

属性值:Double - 元素的高度,以设备独立单位表示(每单位 1/96 英寸)。

元素的高度,以设备独立单位表示(每单位 1/96 英寸)。

 

ActualHeight (只读)
获取该元素的渲染高度。

属性值: Double - 元素的高度,以设备无关单位(每单位1/96英寸)表示。

该属性是基于其他高度输入和布局系统的计算值。该值由布局系统本身设置,基于实际的渲染过程,并且可能会略微滞后于作为输入更改基础的Height等属性的设置值。

由于ActualHeight是一个计算值,因此您应该知道,由于布局系统的各种操作,可能会有多个或增量报告的更改。布局系统可能正在计算子元素所需的测量空间、父元素的约束等。

 

ExtentHeight (只读)
获取包含范围的垂直大小的值。

属性高度:Double - 表示范围垂直大小的 Double。

返回值以设备独立像素描述。

 

ViewportHeight (只读)
获取包含内容视口的垂直大小的值。

属性值: Double - 表示内容视口垂直大小的 Double 值。

返回的值以设备独立像素描述。

 

DesiredSize (只读)
获取元素在布局过程中计算出的尺寸。

属性值: Size - 计算出的尺寸,将成为排列过程的期望尺寸。

仅当IsMeasureValid属性的值为true时,此属性返回的值才是有效的测量值。

在实现布局行为重写(如ArrangeOverride、MeasureOverride或OnRender)时,通常会检查DesiredSize作为测量因素之一(在OnRender情况下,您可能会检查RenderSize,但这取决于您的实现)。根据情况,DesiredSize可能会完全受到您的实现逻辑的尊重,也可能会应用于DesiredSize的约束,并且这些约束还可能改变父元素或子元素的其他特性。例如,支持可滚动区域的控件(但选择不从WPF框架级别的控件派生,而是自己实现)可以将可用大小与DesiredSize进行比较。然后,该控件可以设置一个内部状态,在UI中为该控件启用滚动条。或者,在某些情况下,也可能会忽略DesiredSize。

 

RenderSize获取此元素的最终呈现大小。

属性值:Size - 此元素的呈现大小。

此属性可用于检查布局系统重写(如OnRender或GetLayoutClip)中适用的呈现大小。

更常见的情况是使用类处理程序重写或OnRenderSizeChanged事件处理SizeChanged事件。


在我的情况下,我想知道StackPanel中所有项的期望高度

换句话说:我想知道在绘制之前StackPanel中所有项的高度,并且如果它们溢出面板,我将

  • 删除
  • 缩小
  • 缩放
  • 调整

项目以确保它们适合StackPanel

这意味着我可能想在调整大小事件(SizeChangedLayoutUpdated?)期间获取期望高度(ExtentHeight?DesiredSize?),在任何绘图发生之前(因此更快)。

这些属性中的大多数都返回零;因此,显然有一些我不知道并且未在文档中解释这些属性意味着什么的理解。

2个回答

15

如您所知,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的最终大小。

  • ActualHeightRenderSize.Height完全相同。

为了使用这些属性,您应该仅在LayoutUpdated事件处理程序中访问它们。


6

上面的答案是正确的,除了RenderSize和ActualHeight可能会有临时不同的值。RenderSize在OnRender之前设置,而ActualHeight在WPF完成该控件的布局和渲染处理后设置。在最后,会引发LayoutUpdated事件。

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

顺序如下:

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

WPF可能会执行这个序列多次(递归)。一旦一切都安排妥当,接下来就会执行以下内容:

ActualHeight = RenderSize.Height

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接