【问题标题】:WPF 2 columns layout containerWPF 2列布局容器
【发布时间】:2014-08-17 12:18:56
【问题描述】:

如何创建可以用作ItemsPanelItemsControl 的布局容器 它将项目堆叠在两列中,并将右列用于左列中没有足够空间的剩余项目(类似于与包装面板混合的统一网格)。

例如:

高度几乎相同的四个项目将显示如下:

其中两个宽度明显较小的四个项目将显示如下:

【问题讨论】:

  • 如果剩余的项目不适合右列怎么办?如果您确保这永远不会发生,您可以使用垂直 WrapPanel。

标签: c# wpf wrappanel uniformgrid


【解决方案1】:

尝试垂直方向的 WrapPanel

<WrapPanel Orientation="Vertical" Height="200">
    <Border BorderBrush="Red" BorderThickness="2" Height="100" Width="100"/>
    <Border BorderBrush="Red" BorderThickness="2" Height="100"  Width="100"/>
    <Border BorderBrush="Red" BorderThickness="2" Height="100"  Width="100"/>
    <Border BorderBrush="Red" BorderThickness="2" Height="100"  Width="100"/>
</WrapPanel>

输出

<WrapPanel Orientation="Vertical" Height="200">
    <Border BorderBrush="Red" BorderThickness="2" Height="100" Width="100" />
    <Border BorderBrush="Red" BorderThickness="2" Height="50"  Width="100" />
    <Border BorderBrush="Red" BorderThickness="2" Height="50"  Width="100" />
    <Border BorderBrush="Red" BorderThickness="2" Height="200"  Width="100" />
</WrapPanel>

输出

编辑:正如您的评论所说,wrappanel 不符合您的要求。让我们根据您的要求创建我们的面板。

下面是一个自定义面板,它垂直设置控件,当子项的高度超过面板高度时,它会将子项移动到下一列,与具有垂直方向的 WrapPanel 完全相同,但它具有用户可以在 xaml 中指定的属性 Columns并且面板不会创建超过该列值

CustomPanel.cs

    public class CustomPanel : Panel
{
    //TODO :Create as Attached Property
    public int Columns { get; set; }

    // Default public constructor 
    public CustomPanel(): base()
    {
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        Size size = ArrangeAndMeasure(availableSize, true);
        if (double.IsInfinity(availableSize.Height) || double.IsInfinity(availableSize.Width))
            return size;
        else
            return availableSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        return ArrangeAndMeasure(finalSize, false);
    }

    Size ArrangeAndMeasure(Size finalSize,bool isMeasure)
    {
        //if columns not specified set it value 1.
        Columns = Columns == 0 ? 1 : Columns;
        Size size = new Size(0, 0);
        double maxWidth = 0.0;
        int colCount = 1;

        foreach (UIElement child in InternalChildren)
        {
            if ((size.Height + child.DesiredSize.Height > finalSize.Height) && Columns >= colCount)
            {
                //if all height consumed move to next column
                size.Width += maxWidth;
                size.Height = 0.0;
                colCount++;
            }

            if (isMeasure)
                child.Measure(finalSize);
            else
                child.Arrange(new Rect(new Point(size.Width, size.Height), child.DesiredSize));

            size.Height += child.DesiredSize.Height;

            if (maxWidth < child.DesiredSize.Width)
                maxWidth = child.DesiredSize.Width;
        }
        return size; 
    }
}

xml

 <local:CustomPanel Height="200" Columns="2">
    <Border BorderBrush="LimeGreen" BorderThickness="2" Height="200" Width="100"  />
    <Border BorderBrush="Red" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Black" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Blue" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Yellow" BorderThickness="2" Height="50"  Width="100"  />
</local:CustomPanel>

输出

xaml

 <local:CustomPanel Height="200" Columns="2">
    <Border BorderBrush="Red" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Black" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Blue" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Yellow" BorderThickness="2" Height="50"  Width="100"  />
</local:CustomPanel>

输出

xaml

<local:CustomPanel Height="200" Columns="2">
    <Border BorderBrush="Red" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Black" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Blue" BorderThickness="2" Height="50"  Width="100"  />
    <Border BorderBrush="Yellow" BorderThickness="2" Height="200"  Width="100"  />
</local:CustomPanel>

输出

【讨论】:

  • 感谢您的回答。这样做的问题是,当窗口被调整为更大的宽度时,wrapPanel 会将它们扩展到两列以上,我不希望那样...
  • 查看编辑部分。我希望这会有所帮助。
  • +1 获取详细答案。非常感谢你!我采用了自定义布局方向,但创建了自己的面板,因为您的解决方案对我来说不太适用。不幸的是,由于公司政策,我不能在这里分享我的代码,所以我会接受你的回答。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2016-10-31
  • 1970-01-01
  • 1970-01-01
  • 2019-01-01
  • 2021-08-29
相关资源
最近更新 更多