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
Set max rows in a wrap panel
提问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
回答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:
结果:
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>


