我的应用程序在ItemsControl
中显示使用UniformGrid
作为其ItemsPanel
的多个项目。
<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
属性确实有效,但我需要根据项目数来计算它。获取更新项数的好地方是覆盖OnItemsChanged
代码隐藏中的ItemsControl
方法。但这不会给我实际的项目面板。我在另一个项目中有以下代码,但它总是在这里返回null:
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
所以这也行不通。
走视觉树可能也不是一个选择,因为它太晚了。我需要在排列项目面板之前设置最小高度,以使其不会闪烁。 (我在尺寸变化时生成复杂的内容,因此必须避免任何后期布局。)
我有什么选择可以获得我需要的东西?
如果有可能,我可以放弃UniformGrid
支持别的东西。有什么建议吗?
答案 0 :(得分:3)
您可以采用许多技术来实现这一目标。然而,方法是扩展UniformGrid。
在这种情况下,解决方案是覆盖MeasureOverride()
以根据行中所有子项的最小高度或更大的MinRowHeight来计算新大小。
用法:
<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;
}
}
}
}
答案 1 :(得分:0)
UniformGrid
执行非常精确的任务...为所有项目提供完全相同大小的空间来渲染自己。如果您不需要该功能,那么您使用了错误的Panel
。请尝试使用WrapPanel
Class,这样可以更好地处理不同大小的孩子:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
答案 2 :(得分:0)
我发现前段时间我用以下代码解决了这个问题。我的应用程序中有一个派生类,因此我可以覆盖MeasureOverride
的{{1}}方法。
ItemsControl
我班级的XAML代码如下:
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;
}
}