【问题标题】:WPF: How to make two controls (list views) share whole available space between them?WPF:如何使两个控件(列表视图)在它们之间共享整个可用空间?
【发布时间】:2014-07-05 16:15:27
【问题描述】:

我有两个列表视图(垂直对齐),其中可能包含不同数量的项目。我希望他们在需要时按比例共享空间(这可以通过常规网格和 * 来实现)但是当一个列表视图没有很多项目要显示时,我希望其他列表视图填充整个空间。反之亦然。

尝试了不同的方法,但无法实现此行为。

例如,我可以使用网格指定 * 和 *(或其他比例),但这意味着如果一个列表视图没有任何项目(而另一个有大量项目),那么一半的空间将是空的。

有没有办法做到这一点?我需要为此实现我自己的面板还是有另一种(更简单)的方法来做到这一点?

谢谢! 扎基

【问题讨论】:

  • 当没有一个列表视图有足够的项目来填满整个空间时会是什么样子?
  • 那么有空就可以了。我的目标是在需要时使用整个空间...更新:顶部列表视图显示停靠到顶部和底部到底部...
  • 如果列表视图下方可以留空,只需将它们放入<StackPanel Orientation="Vertial">
  • 不确定我是否理解它是如何工作的。我相信如果第一个列表视图有很多项目,它将占用整个可用空间。在这种情况下,我需要共享 50/50 的空间。

标签: wpf listview resize panel space


【解决方案1】:

只是想分享我想要的最终版本。感谢 torvin 提供正确的方向,感谢您快速而有价值的回复!

================================================ ===================

以这样的方式实现了主窗口的大小调整:

  1. 如果有未使用的空间,任何列表视图都可以使用它(因此,没有未使用的区域同时带有滚动条)
  2. 如果空间不足,则底部控件至少占用 100 像素和/或顶部控件至少占用高度 - 100 像素
  3. 顶部控件停靠在顶部,底部控件停靠在底部

================================================ ===================

/// <summary>The two children effecient panel.</summary>
public class TwoChildrenEffecientPanel : Panel
{
    #region Constants and Fields

    /// <summary>The bottom child min size.</summary>
    private const double BottomChildMinSize = 110;

    #endregion

    #region Methods

    /// <summary>The arrange override.</summary>
    /// <param name="arrangeSize">The arrange size.</param>
    /// <returns>The <see cref="Size"/>.</returns>
    protected override Size ArrangeOverride(Size arrangeSize)
    {
        Debug.Assert(this.InternalChildren.Count == 2, "This custom panel supports only two children.");

        UIElement top = this.InternalChildren[0];
        var topRect = new Rect(arrangeSize);
        topRect.Height = top.DesiredSize.Height;
        top.Arrange(topRect);

        UIElement bottom = this.InternalChildren[1];
        var bottomRect = new Rect(arrangeSize);
        bottomRect.Height = bottom.DesiredSize.Height;
        bottomRect.Y = arrangeSize.Height - bottomRect.Height;
        bottom.Arrange(bottomRect);

        return arrangeSize;
    }

    /// <summary>The measure override.</summary>
    /// <param name="constraint">The constraint.</param>
    /// <returns>The <see cref="Size"/>.</returns>
    protected override Size MeasureOverride(Size constraint)
    {
        Debug.Assert(this.InternalChildren.Count == 2, "This custom panel supports only two children.");

        // First measure desired size of all children.
        var availableSize = new Size(constraint.Width, double.PositiveInfinity);
        foreach (UIElement ui in this.InternalChildren)
        {
            ui.Measure(availableSize);
        }

        // Put constraints only if space is not enough
        double totalHeight = this.InternalChildren.OfType<UIElement>().Sum(x => x.DesiredSize.Height);
        if (totalHeight > constraint.Height)
        {
            UIElement top = this.InternalChildren[0];
            UIElement bottom = this.InternalChildren[1];

            if (bottom.DesiredSize.Height < BottomChildMinSize)
            {
                // If the second control needs less than it can get then put contraint only on the first one
                top.Measure(new Size(constraint.Width, Math.Max(constraint.Height - bottom.DesiredSize.Height, 0)));
            }
            else if (top.DesiredSize.Height < constraint.Height - BottomChildMinSize)
            {
                // If the first control needs less than it can get then put contraint only on the second one
                bottom.Measure(new Size(constraint.Width, Math.Max(constraint.Height - top.DesiredSize.Height, 0)));
            }
            else
            {
                top.Measure(new Size(constraint.Width, Math.Max(constraint.Height - BottomChildMinSize, 0)));
                bottom.Measure(new Size(constraint.Width, BottomChildMinSize));
            }
        }

        double maxWidth = this.InternalChildren.OfType<UIElement>().Max(x => x.DesiredSize.Width);
        return new Size(Math.Min(constraint.Width, maxWidth), Math.Min(constraint.Height, totalHeight));
    }

    #endregion
}

【讨论】:

    【解决方案2】:

    好的,试试这个代码:

    class MyPanel : Panel
    {
        protected override Size MeasureOverride(Size constraint)
        {
            // first measuring desired size of children
            var availableSize = new Size(constraint.Width, double.PositiveInfinity);
            foreach (UIElement ui in InternalChildren)
                ui.Measure(availableSize);
    
            var totalHeight = InternalChildren.OfType<UIElement>().Sum(x => x.DesiredSize.Height);
    
            // now resizing children within constraint
            var factor = (totalHeight == 0 ? 1.0 : constraint.Height / totalHeight);
            foreach (UIElement ui in InternalChildren)
                ui.Measure(new Size(constraint.Width, ui.DesiredSize.Height * factor));
    
            var maxWidth = InternalChildren.OfType<UIElement>().Max(x => x.DesiredSize.Width);
            return new Size(Math.Min(constraint.Width, maxWidth), Math.Min(constraint.Height, totalHeight));
        }
    
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            // aligning children vertically 
    
            var totalHeight = InternalChildren.OfType<UIElement>().Sum(ui => ui.DesiredSize.Height);
            var y = 0.0;
            var rect = new Rect(arrangeSize);
    
            foreach (UIElement ui in InternalChildren)
            {
                rect.Y += y;
                y = ui.DesiredSize.Height;
                rect.Height = y;
                ui.Arrange(rect);
            }
    
            return arrangeSize;
        }
    }
    

    此面板将垂直排列子级,并按比例为子级提供与其所需高度成比例的垂直空间,但不会让他们占用比可用空间更多的空间。

    因此,例如,如果您有 200px 高度可用,第一个列表视图需要 150px,第二个需要 100px,它们将被缩小到 120px + 80px == 200px

    【讨论】:

    • (在我的解决方案中,我添加了一个只有两个孩子的约束,并且还使用了自己的自定义比例,而不是依赖基于内容的因素{后者导致当有 1000 个与 10 个项目时行为不佳})。再次感谢您。
    猜你喜欢
    • 2011-12-24
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多