【问题标题】:Stackpanel: Height vs ActualHeight vs ExtentHeight vs ViewportHeight vs DesiredSize vs RenderSizeStackpanel:Height vs ActualHeight vs ExtentHeight vs ViewportHeight vs DesiredSize vs RenderSize
【发布时间】:2011-09-18 04:29:32
【问题描述】:

我想知道我的StackPanel 中所有物品的高度。

有什么区别:

  • Height - 获取或设置元素的建议高度。
  • ActualHeight - 获取此元素的渲染高度。 (只读)
  • ExtentHeight - 获取一个包含范围垂直大小的值。 (只读)
  • ViewportHeight - 获取一个包含内容视口垂直大小的值。 (只读)
  • DesiredSize - 获取此元素在布局过程的测量过程中计算的大小。 (只读)
  • RenderSize - 获取(或设置,但参见备注)此元素的最终渲染大小。

来自 MSDN:

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

属性值: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

这意味着我可能想在 resize 事件(SizeChanged?LayoutUpdated?)期间获得 desired 高度(ExtentHeight?DesiredSize?) - 在任何之前绘图发生(所以它更快)。

这些属性中的大多数返回零;所以显然对这些属性的含义有一些理解,我不知道,也没有在文档中解释。

【问题讨论】:

    标签: wpf layout height scaling stackpanel


    【解决方案1】:

    如您所知,StackPanel 是一个 [Panel] 对象。每个面板通过两种方法与其子面板进行通信以确定最终尺寸和位置。 第一种方法是MeasureOverride,第二种方法是ArrangeOverride

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

    让我们创建一个堆栈面板:

    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) 返回的是 sum 方向的儿童尺寸 StackPanel 和最大的大小 另一个方向的孩子。

    • RenderSize代表最终 布局后StackPanel 的大小 完成了。

    • ActualHeightRenderSize.Height

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

    【讨论】:

      【解决方案2】:

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

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

      顺序如下:

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

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

      ActualHeight = RenderSize.Height
      

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

      【讨论】:

        猜你喜欢
        • 2014-08-17
        • 1970-01-01
        • 2012-07-27
        • 1970-01-01
        • 2010-12-09
        • 2017-06-20
        • 2012-08-07
        相关资源
        最近更新 更多