.net 具有每行最小高度的UniformGrid

.net 具有每行最小高度的UniformGrid,.net,wpf,layout,.net,Wpf,Layout,我的应用程序在ItemsControl中显示多个项目,该控件使用UniformGrid作为其ItemsPanel <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <!-- Arrange all items vertically, distribute the space evenly --> <UniformGrid Columns="1"/> <

我的应用程序在
ItemsControl
中显示多个项目,该控件使用
UniformGrid
作为其
ItemsPanel

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <!-- Arrange all items vertically, distribute the space evenly -->
        <UniformGrid Columns="1"/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
所以这也不起作用

在可视化树上行走可能也不是一个选项,因为为时已晚。我需要先设置最小高度,然后再安排项目面板,这样它就不会闪烁。(我在更改大小时生成复杂内容,因此必须避免任何延迟布局。)

我需要什么样的选择才能得到我所需要的


如果可能的话,我可能会放弃UniformGrid,而选择其他内容。有什么建议吗?

A
UniformGrid
执行一项非常精确的任务。。。为所有项目提供完全相同大小的空间以进行渲染。如果不需要该功能,则使用的
面板不正确。请尝试使用,它可以更好地处理不同大小的孩子:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <WrapPanel />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

您可以使用许多技术来实现这一点。然而,在方法上,我们需要扩展UniformGrid

这种情况下的解决方案是重写
MeasureOverride()
,根据行中所有子项的最小高度或最小行高计算新的大小,该值越大越好

用法:

<UserControl x:Class="SOF.UniformGridMinHeight"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:sof="clr-namespace:SOF"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<sof:UniformGridEx Columns="3" MinRowHeight="100">
        <Border Background="Red"/>
        <Border Background="Blue"/>
        <Border Background="Green"/>
        <Border Background="Yellow"/>
        <Border Background="Pink"/>
        <Border Background="Purple"/>
        <Border Background="LightCoral"/>
        <Border Background="DimGray"/>
        <Border Background="OrangeRed"/>
        <Border Background="Olive"/>
        <Border Background="Salmon"/>
</sof:UniformGridEx>

扩展的UniformGrid:

public class UniformGridEx : UniformGrid
{
    public static readonly DependencyProperty MinRowHeightProperty = DependencyProperty.Register(
        "MinRowHeight", typeof(double), typeof(UniformGrid), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure));

    private int _columns;
    private int _rows;

    public double MinRowHeight
    {
        get { return (double)GetValue(MinRowHeightProperty); }
        set { SetValue(MinRowHeightProperty, value); }
    }

    protected override Size MeasureOverride(Size constraint)
    {
        UpdateComputedValues();
        var calculatedSize = base.MeasureOverride(constraint);
        if (MinRowHeight > 0)
        {
            calculatedSize = new Size(calculatedSize.Width, Math.Max(calculatedSize.Height, _rows * MinRowHeight));
        }
        return calculatedSize;
    }

    private void UpdateComputedValues()
    {
        _columns = Columns;
        _rows = Rows;

        if (FirstColumn >= _columns)
        {
            FirstColumn = 0;
        }

        if ((_rows == 0) || (_columns == 0))
        {
            int nonCollapsedCount = 0;

            for (int i = 0, count = InternalChildren.Count; i < count; ++i)
            {
                UIElement child = InternalChildren[i];
                if (child.Visibility != Visibility.Collapsed)
                {
                    nonCollapsedCount++;
                }
            }

            if (nonCollapsedCount == 0)
            {
                nonCollapsedCount = 1;
            }

            if (_rows == 0)
            {
                if (_columns > 0)
                {
                    _rows = (nonCollapsedCount + FirstColumn + (_columns - 1)) / _columns;
                }
                else
                {
                    _rows = (int)Math.Sqrt(nonCollapsedCount);
                    if ((_rows * _rows) < nonCollapsedCount)
                    {
                        _rows++;
                    }
                    _columns = _rows;
                }
            }
            else if (_columns == 0)
            {
                _columns = (nonCollapsedCount + (_rows - 1)) / _rows;
            }
        }
    }
}
公共类UniformGridEx:UniformGrid
{
公共静态只读DependencyProperty MinRowHeightProperty=DependencyProperty.Register(
“最小行高”、typeof(double)、typeof(UniformGrid)、新的FrameworkPropertyMetadata(0d,FrameworkPropertyMetadata选项。影响度量));
专用int_列;
私有整数行;
公共双排高度
{
获取{return(double)GetValue(MinRowHeightProperty);}
set{SetValue(MinRowHeightProperty,value);}
}
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
updateComputerdValues();
var calculatedSize=基本测量值超出(约束);
如果(最小行高>0)
{
calculatedSize=新大小(calculatedSize.Width,Math.Max(calculatedSize.Height,_rows*MinRowHeight));
}
返回计算的大小;
}
私有void updateComputerdValues()
{
_列=列;
_行=行;
如果(第一列>=\u列)
{
第一列=0;
}
如果(_行==0)| |(_列==0))
{
int noncollecsedCount=0;
for(int i=0,count=InternalChildren.count;i0)
{
_行=(nonCollapsedCount+FirstColumn+(\u columns-1))/\u列;
}
其他的
{
_行=(int)Math.Sqrt(nonCollapsedCount);
if((_行*_行)
我发现我不久前已经用以下代码解决了这个问题。我的应用程序中有一个派生类,因此我可以重写
ItemsControl
MeasureOverride
方法

class MyItemsControl : ItemsControl
{
    // ...

    protected override Size MeasureOverride(Size constraint)
    {
        Size size = base.MeasureOverride(constraint);

        // Keep minimum height per item
        int minHeight = Items.Count * 250;
        if (size.Height < minHeight)
        {
            size.Height = minHeight;
        }
        return size;
    }
}
类MyItemsControl:ItemsControl
{
// ...
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
尺寸=基准测量超越(约束);
//保持每件物品的最低高度
int minHeight=Items.Count*250;
如果(尺寸高度<最小高度)
{
尺寸。高度=最小高度;
}
返回大小;
}
}
我的类的XAML代码如下所示:

<ItemsControl x:Class="MyItemsControl">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <!-- Arrange all items vertically, distribute the space evenly -->
            <UniformGrid Columns="1"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <!-- Templates and other stuff ... -->
</ItemsControl>

查看答案,看看是否有用。只要有足够的空间,我就需要填充功能。即使空间太小,也应该在所有物品之间均匀分布。他们需要伸展整个宽度。包装袋永远无法做到这一点,它总是将物品保持尽可能小。
<ItemsControl x:Class="MyItemsControl">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <!-- Arrange all items vertically, distribute the space evenly -->
            <UniformGrid Columns="1"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <!-- Templates and other stuff ... -->
</ItemsControl>