首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有每行MinHeight的UniformGrid

具有每行MinHeight的UniformGrid
EN

Stack Overflow用户
提问于 2015-06-02 21:05:35
回答 3查看 2K关注 0票数 2

我的应用程序在使用UniformGrid作为其ItemsPanelItemsControl中显示多个项。

代码语言:javascript
复制
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <!-- Arrange all items vertically, distribute the space evenly -->
        <UniformGrid Columns="1"/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

现在,每个项目将占用尽可能多的空间和完整的宽度。事情应该是这样的。但是每一项都不能小于一定的高度,比如250像素。因此,我的ItemsControl被放在一个ScrollViewer中,如果屏幕上的最小高度不再适合,它将开始滚动(但在此之前填充)。

将每一项的MinHeight属性设置为250将使其更高,但不会改变UniformGrid以任何方式排列它们的方式,因此它们将被裁剪。这不是解决方案。

设置整个ItemsControl或UniformGrid的MinHeight属性确实可以,但我需要根据项的数量来计算它。获取更新后的项数的一个好方法是覆盖我的ItemsControl代码隐藏中的OnItemsChanged方法。但这不会给我实际的项目面板。我在另一个项目中有以下代码,但它在这里总是返回null:

代码语言:javascript
复制
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);

因此,这也不起作用。

遍历可视化树可能也不是一个选择,因为为时已晚。我需要在排列项目面板之前设置最小高度,这样它就不会闪烁。(我会在更改大小时生成复杂的内容,因此必须避免任何后期布局。)

我有什么选择才能得到我需要的东西?

如果可能的话,我可能会放弃UniformGrid,转而使用其他东西。有什么建议吗?

EN

回答 3

Stack Overflow用户

发布于 2015-06-03 05:50:56

您可以使用许多技术来实现这一点。但是,方法上是扩展UniformGrid。

这种情况下的解决方案是覆盖MeasureOverride(),根据行中所有子项的最小高度或MinRowHeight计算新的大小,以较大者为准。

用法:

代码语言:javascript
复制
<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:

代码语言:javascript
复制
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;
            }
        }
    }
}
票数 3
EN

Stack Overflow用户

发布于 2015-06-02 21:16:00

UniformGrid执行一个非常精确的任务...为所有项目提供完全相同大小的空间来呈现它们自己。如果您不需要该功能,那么您使用的Panel是错误的。尝试使用WrapPanel Class,它可以更好地处理不同大小的子项:

代码语言:javascript
复制
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <WrapPanel />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
票数 0
EN

Stack Overflow用户

发布于 2015-09-23 18:23:54

我发现不久前我已经用下面的代码解决了这个问题。我的应用程序中有一个派生类,因此我可以覆盖ItemsControlMeasureOverride方法。

代码语言:javascript
复制
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;
    }
}

我的类的XAML代码如下所示:

代码语言:javascript
复制
<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>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30596993

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档