wpf 在包装面板中设置最大行数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11636396/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 04:42:39  来源:igfitidea点击:

Set max rows in a wrap panel

c#wpfxamlpanelwrappanel

提问by Darf Zon

I need to configure a wrap panel where I can set the max rows or max columns in it.

我需要配置一个环绕面板,我可以在其中设置最大行数或最大列数。

This is really necessary, I'm using WPF 4.0. But the another day, I was programmin Metro applications and I remember that one of its controls has this properties, but in WPF not (until I know).

这真的很有必要,我正在使用 WPF 4.0。但是另一天,我正在编写 Metro 应用程序,我记得它的一个控件具有此属性,但在 WPF 中没有(直到我知道)。

Is exists such control in WPF 4.0? Or do I need to create a new one?

WPF 4.0 中是否存在这样的控件?还是我需要创建一个新的?

采纳答案by Akash KC

You can set ItemHeightand ItemWidthproperties to set the max rows and columns...

您可以设置ItemHeightItemWidth属性来设置最大行和列...

For more info, have a look here

欲了解更多信息,请看这里

回答by frakon

Here is an implementationof such a WrapPanel.

这是这种 WrapPanel的实现

Xaml:

Xml:

<loc:WrapPanelWithRowsOrColumnsCount
    xmlns:loc="clr-namespace:..."
    Orientation="Vertical"
    RowsOrColumnsCount="2">
    <TextBox Text="Andrew" Margin="2" Height="30" />
    <TextBox Text="Betty" Margin="2" Height="40" />
    <TextBox Text="Celine" Margin="2" Height="20" />
    <TextBox Text="Dick" Margin="2" Height="20" />
    <TextBox Text="Enron" Margin="2" Height="30" />
    <TextBox Text="Felix" Margin="2" Height="20" />
    <TextBox Text="Hanibal" Margin="2" Height="30" />
</loc:WrapPanelWithRowsOrColumnsCount>

Result:

结果:

enter image description here

在此处输入图片说明

Codeof WrapPanelWithRowsOrColumnsCount.cs:

代码WrapPanelWithRowsOrColumnsCount.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

public class WrapPanelWithRowsOrColumnsCount : WrapPanel
{
    public static readonly DependencyProperty RowsOrColumnsCountProperty = 
        DependencyProperty.Register(
            "RowsOrColumnsCount",
            typeof(int),
            typeof(WrapPanelWithRowsOrColumnsCount),
            new PropertyMetadata(int.MaxValue));

    public int RowsOrColumnsCount
    {
        get { return (int)GetValue(RowsOrColumnsCountProperty); }
        set { SetValue(RowsOrColumnsCountProperty, Math.Max(value, 1)); }
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        if (Children.Count > 0)
        {
            Size newAvailableSize;

            if (Orientation == Orientation.Horizontal)
            {
                var suitableWidth = EstimateSuitableRowOrColumnLength(Children.Cast<UIElement>(),
                                                                        true,
                                                                        availableSize,
                                                                        RowsOrColumnsCount);

                newAvailableSize = 
                    double.IsNaN(suitableWidth) || suitableWidth <= 0
                        ? availableSize 
                        : new Size(Math.Min(suitableWidth, availableSize.Width), availableSize.Height);
            }
            else
            {
                var suitableHeigth = EstimateSuitableRowOrColumnLength(Children.Cast<UIElement>(),
                                                                        false,
                                                                        availableSize,
                                                                        RowsOrColumnsCount);
                newAvailableSize =
                    double.IsNaN(suitableHeigth) || suitableHeigth <= 0
                        ? availableSize
                        : new Size(availableSize.Width, Math.Min(suitableHeigth, availableSize.Height));
            }

            return base.MeasureOverride(newAvailableSize);
        }
        else
        {
            return base.MeasureOverride(availableSize);
        }
    }

    private double EstimateSuitableRowOrColumnLength(IEnumerable<UIElement> elements,
                                                        bool trueRowsFalseColumns,
                                                        Size availableSize,
                                                        int rowsOrColumnsCount)
    {
        var elementsList = elements.ToList();

        var desiredLengths = elementsList.Select(el => DesiredLength(el, availableSize, trueRowsFalseColumns)).ToList();

        var maxLength = desiredLengths.Where(length => !double.IsNaN(length)).Concat(new[] { 0.0 }).Max();

        if (maxLength <= 0.0)
        {
            return double.NaN;
        }

        var desiredLengthsRepaired = desiredLengths.Select(length => double.IsNaN(length) ? maxLength : length).ToList();

        var totalDesiredLength = desiredLengthsRepaired.Sum();

        var maxCount = Math.Min(rowsOrColumnsCount, elementsList.Count);

        var suitableRowOrColumnLength = totalDesiredLength / maxCount;

        double nextLengthIncrement;

        while (CountRowsOrColumnsNumber(desiredLengthsRepaired, suitableRowOrColumnLength, out nextLengthIncrement) > maxCount)
        {
            suitableRowOrColumnLength += nextLengthIncrement;
        }

        suitableRowOrColumnLength = Math.Max(suitableRowOrColumnLength, desiredLengthsRepaired.Max());

        return suitableRowOrColumnLength;
    }

    private int CountRowsOrColumnsNumber(List<double> desiredLengths, double rowOrColumnLengthLimit, out double nextLengthIncrement)
    {
        int rowOrColumnCount = 1;
        double currentCumulativeLength = 0;
        bool nextNewRowOrColumn = false;

        var minimalIncrement = double.MaxValue;

        foreach (var desiredLength in desiredLengths)
        {
            if (nextNewRowOrColumn)
            {
                rowOrColumnCount++;
                currentCumulativeLength = 0;
                nextNewRowOrColumn = false;
            }

            if (currentCumulativeLength + desiredLength > rowOrColumnLengthLimit)
            {
                minimalIncrement = Math.Min(minimalIncrement,
                                            currentCumulativeLength + desiredLength - rowOrColumnLengthLimit);

                if (currentCumulativeLength == 0)
                {
                    nextNewRowOrColumn = true;
                    currentCumulativeLength = 0;
                }
                else
                {
                    rowOrColumnCount++;
                    currentCumulativeLength = desiredLength;
                }
            }
            else
            {
                currentCumulativeLength += desiredLength;
            }
        }

        nextLengthIncrement = minimalIncrement != double.MaxValue ? minimalIncrement : 1;

        return rowOrColumnCount;
    }

    private double DesiredLength(UIElement el, Size availableSize, bool trueRowsFalseColumns)
    {
        el.Measure(availableSize);
        Size next = el.DesiredSize;

        var length = trueRowsFalseColumns ? next.Width : next.Height;

        if (Double.IsInfinity(length) ||
            Double.IsNaN(length))
        {
            return Double.NaN;
        }
        else
        {
            return length;
        }
    }
}

The solution was inspired by this codeproject article.

该解决方案的灵感来自这篇 codeproject 文章

回答by Tim

The only way I can think you could do this with the WrapPanel is if you know the size of the objects (and they're consistent), so you could set the height/width of the WrapPanel accordingly. That's pretty ugly though.

我认为您可以使用 WrapPanel 执行此操作的唯一方法是,如果您知道对象的大小(并且它们是一致的),那么您可以相应地设置 WrapPanel 的高度/宽度。不过还是挺丑的。

One thing to think about: What do you want the panel to do with the elements beyond that maximum number of rows/columns? Or is there always the right number of elements? If that's the case, then you should really look at the Grid instead.

要考虑的一件事:您希望面板对超出最大行/列数的元素做什么?或者总是有正确数量的元素?如果是这种情况,那么您应该真正查看 Grid。

回答by Wolfgang Ziegler

I think for what you are trying to accomplish the WPF Grid is the better solution. By setting a specific count of grid rows you can simulate that behaviour of a wrap panel and it is more flexibel.

我认为对于您想要完成的 WPF 网格是更好的解决方案。通过设置特定的网格行数,您可以模拟环绕面板的行为,并且它更加灵活。

<Grid>
  <Grid.ColumnDefinitions>
    <ColumDefinition Height="Auto"/>
    <ColumDefinition Height="Auto"/>
    <ColumDefinition Height="Auto"/>
    .... 
    <ColumDefinition Height="*/>  
  </Grid.ColumnDefinitions>
<Grid>