Wpf Listbox—满足最大行数之前的内容大小
我希望有一个列表框,其大小与其内容相符,直到满足某些MaxRow属性。因此,如果MaxRow值为3,则其行为如下 Items.Count==0->SizeToContent Items.Count==1->SizeToContent Items.Count==2->SizeToContent Items.Count==3->SizeToContent Items.Count==4->将高度限制为3行并启用滚动条 Items.Count==5->将高度限制为3行并启用滚动条 等等 我认为正确的方法是使用自定义面板(如下所示),但这似乎不起作用 我怎样才能做到这一点Wpf Listbox—满足最大行数之前的内容大小,wpf,listbox,panel,Wpf,Listbox,Panel,我希望有一个列表框,其大小与其内容相符,直到满足某些MaxRow属性。因此,如果MaxRow值为3,则其行为如下 Items.Count==0->SizeToContent Items.Count==1->SizeToContent Items.Count==2->SizeToContent Items.Count==3->SizeToContent Items.Count==4->将高度限制为3行并启用滚动条 Items.Count==5->将高度限制为3行并启用滚动条 等等 我认为正确的方法
<ListBox ItemsSource="{Binding Items}"
HorizontalContentAlignment="Stretch">
<ListBox.Template>
<ControlTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<l:LimitingStackPanel VerticalAlignment="Top"
IsItemsHost="True"/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
</ListBox>
public class LimitingStackPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
Size measuredSize = new Size(0, 0);
int count = 0;
foreach(UIElement item in InternalChildren)
{
item.Measure(availableSize);
measuredSize.Width = Math.Max(measuredSize.Width, item.DesiredSize.Width);
if(++count <= 4)
{
measuredSize.Height += item.DesiredSize.Height;
}
}
return measuredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
double y = 0;
foreach (UIElement item in InternalChildren)
{
double height = item.DesiredSize.Height;
item.Arrange(new Rect(0, y, finalSize.Width, height));
y += height;
}
return new Size(finalSize.Width, y);
}
}
公共类限制StackPanel:面板
{
受保护的覆盖尺寸测量覆盖(尺寸可用尺寸)
{
尺寸测量尺寸=新尺寸(0,0);
整数计数=0;
foreach(InternalChildren中的UIElement项)
{
项目.措施(可用性);
measuredSize.Width=Math.Max(measuredSize.Width,item.DesiredSize.Width);
如果(++count我试图通过附加属性来解决它,因此将其作为行为
样本xaml
<StackPanel xmlns:l="clr-namespace:CSharpWPF">
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
<ListBoxItem>item 4</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
<ListBoxItem>item 4</ListBoxItem>
<ListBoxItem>item 5</ListBoxItem>
</ListBox>
</StackPanel>
结果是一个自动高度列表框,最多可显示指定数量的项目
此解决方案假定所有项目的大小都相同。最后,对于这个问题,它不是一个完美的解决方案,我可以说它是一个解决方法。还值得注意的是,它只能在运行时重新调整大小,而在设计时它是无效的
尝试一下,看看这与您的需求有多接近
如果您事先知道项目高度,那么更好的解决方案是使用MaxHeight
属性我试图通过附加属性来解决它,因此将其作为行为
样本xaml
<StackPanel xmlns:l="clr-namespace:CSharpWPF">
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
<ListBoxItem>item 4</ListBoxItem>
</ListBox>
<ListBox l:ListBoxHelper.AutoSizeItemCount="3">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
<ListBoxItem>item 4</ListBoxItem>
<ListBoxItem>item 5</ListBoxItem>
</ListBox>
</StackPanel>
结果是一个自动高度列表框,最多可显示指定数量的项目
此解决方案假定所有项目的大小都相同。最后,对于这个问题,它不是一个完美的解决方案,我可以说它是一个解决方法。还值得注意的是,它只能在运行时重新调整大小,而在设计时它是无效的
尝试一下,看看这与您的需求有多接近
如果您提前知道项目高度,那么更好的解决方案是使用MaxHeight
属性您希望限制ListBox或底层LimitingStackPanel的大小?无论哪一个解决问题的方法最好,让我们看看是否有合适的解决方案。在开始之前,请告诉我如果内容大小不同?它应该限制为3个完整的项目,对吗?滚动行为如何?逐项滚动?如果元素大小不同,是否允许列表框的大小在滚动时改变?我认为只有假设所有项目始终具有相同的高度,这个想法才会行得通。它还需要与可视化一起工作,所以我猜它是w我必须按项目滚动。我已经用一张图片更新了这个问题,显示了我正在努力实现的目标。您希望限制ListBox或底层LimitingStackPanel的大小?无论哪一个最好的解决方案似乎都非常棘手,让我们看看是否有一个合适的解决方案。在我开始之前,告诉我如果内容大小不同,该怎么办?这很简单你可以限制为3个完整的项目,对吗?滚动的行为如何?逐项滚动?如果元素大小不同,是否允许列表框的大小在滚动时发生变化?我认为只有假设所有项目始终具有相同的高度,这个想法才会行得通。它还需要与可视化一起工作,所以我猜它将不得不改变oll by item。我已经用一个图片更新了问题,显示了我试图实现的目标。我稍微修改了它,以便更好地处理大型集合(请参见我的编辑),谢谢!。我稍微修改了它,以便更好地处理大型集合(请参见我的编辑)
namespace CSharpWPF
{
public class ListBoxHelper : DependencyObject
{
public static int GetAutoSizeItemCount(DependencyObject obj)
{
return (int)obj.GetValue(AutoSizeItemCountProperty);
}
public static void SetAutoSizeItemCount(DependencyObject obj, int value)
{
obj.SetValue(AutoSizeItemCountProperty, value);
}
// Using a DependencyProperty as the backing store for AutoSizeItemCount. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AutoSizeItemCountProperty =
DependencyProperty.RegisterAttached("AutoSizeItemCount", typeof(int), typeof(ListBoxHelper), new PropertyMetadata(0, OnAutoSizeItemCountChanged));
private static void OnAutoSizeItemCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListBox listBox = d as ListBox;
listBox.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler((lb, arg) => UpdateSize(listBox)));
listBox.ItemContainerGenerator.ItemsChanged += (ig, arg) => UpdateSize(listBox);
}
static void UpdateSize(ListBox listBox)
{
ItemContainerGenerator gen = listBox.ItemContainerGenerator;
FrameworkElement element = listBox.InputHitTest(new Point(listBox.Padding.Left + 5, listBox.Padding.Top + 5)) as FrameworkElement;
if (element != null && gen != null)
{
object item = element.DataContext;
if (item != null)
{
FrameworkElement container = gen.ContainerFromItem(item) as FrameworkElement;
if (container == null)
{
container = element;
}
int maxCount = GetAutoSizeItemCount(listBox);
double newHeight = Math.Min(maxCount, gen.Items.Count) * container.ActualHeight;
newHeight += listBox.Padding.Top + listBox.Padding.Bottom + listBox.BorderThickness.Top + listBox.BorderThickness.Bottom + 2;
if (listBox.ActualHeight != newHeight)
listBox.Height = newHeight;
}
}
}
}
}