不要在WPF列表框中显示部分项目

7
我尝试了Google和Bing,但没有任何结果。这里是否有人知道如何防止WPF中ListBox中出现部分项?举个例子:ListBox高度为200像素-每个项目高度为35像素。这意味着我可以显示5.7个项目。0.7个项目是不可取的。我想将其限制为仅显示5个项目。然后用户可以滚动以查看其他项目。
我的问题是:A)我应该尝试动态调整ListBox或ScrollViewer ViewPort的大小,使其完美适合吗?还是B)实现自定义面板,该面板不会安排其所需高度大于剩余垂直空间的子元素?
希望能得到您的想法。最后注意:如果有人知道第三方控件(listbox或grid)可以做到这一点,我也很感兴趣。

嗯,WinForms中ListBox有一个设置:IntegralHeight AFAIK,WPF ListBox没有。 - Muad'Dib
5个回答

1

只需在设计师中调整大小,直到不再出现部分行即可。实现自定义面板对于这样的事情来说太过繁琐。

您也可以尝试使用ListView而不是ListBox。我可能记错了,但我认为ListView不会显示部分行,或者可能有一个选项可以不显示部分行。


我会查看列表视图。我们无法预设列表框的大小。当/如果用户调整窗口大小时,它的高度将会增加。 - David Martin
3
大卫,你做得很好,能够正确处理调整大小的问题!不这样做是我很反感的一件事情。 - Scott J
我们的列表框项目是互动的(它们有数字上/下微调按钮)。当在底部显示90%的项目时,用户试图单击上/下按钮并且WPF会友好地重新定位该项目。现在他们的鼠标移到了下一个项目上。如果他们没有意识到,他们将编辑错误的项目。 - David Martin
@David:这完全有道理。我很抱歉参与了标准的StackOverflow行为,认为我比提问者更懂。根据你所描述的情况,我可能会使用自定义控件,它可以包装或继承自Panel。 - MusiGenesis
虽然我不得不提一下我有多么讨厌旋转按钮。 :) - MusiGenesis
显示剩余2条评论

1

今天我一直在思考这个问题,因为我的项目一直在解决这个问题。我的想法与我的项目有关,但应该适用于其他情况。我假设使用MVVM ViewModel,但它也可以不用。

将一个属性绑定到包含ListBox的容器的高度,然后使用ValueConverter将ListBox的高度绑定到该属性,以使ListBox根据单个项的高度分阶段地扩展或缩小。当调整大小时,这可能看起来有点奇怪,但通过简短的动画可以看起来很好。


你能否对这个答案再多解释一些细节? - Roger Lipscombe
我会尝试在这个周末提供一个简单的示例。 - Mike B

1

你可以通过在调度程序中找到列表框内容的实际高度并调整列表框的高度来实现此目的,但这将使列表框的大小根据实现而增长或缩小。


1

我的建议是为每个项目创建一个自定义面板。如果该面板无法完全显示,则不显示该面板。列表可以根据需要调整大小,因为它的唯一工作是成为可调整大小的容器,为面板提供区域。面板可以根据需要增长和缩小。


0
我的解决方案是使用多值转换器,它以ListBoxScrollViewer和层次结构中的ListBoxItem作为输入,还包括列表框ActualHeight、滚动查看器VerticalOffset和列表框项ActualHeight,并返回一个可见性。最后两个(双重)值仅用于确保转换器的Convert方法在任何重要值更改时都会被调用。基本上,如果项目底部大于滚动查看器底部,则返回的VisibilityHidden,否则为Visible

以下是转换器的代码:

using System;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

public class ListBoxItemToVisibilityConverter : IMultiValueConverter
{
    public object Convert(
        object[] values,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        if ((values?.Length ?? 0) != 6)
            return Visibility.Collapsed;

        var listBox = values.OfType<ListBox>().FirstOrDefault();
        var scrollViewer = values.OfType<ScrollViewer>().FirstOrDefault();
        var listBoxItem = values.OfType<ListBoxItem>().FirstOrDefault();

        var heights = values.OfType<double>().ToArray();

        if (new object[] { listBox, scrollViewer, listBoxItem }.Any(item => item == null) || heights.Length != 3)
            return Visibility.Collapsed;

        var scrollViewerBottom = scrollViewer.PointToScreen(new Point(0, scrollViewer.ActualHeight)).Y;
        var listBoxItemBottom = listBoxItem.PointToScreen(new Point(0, listBoxItem.ActualHeight)).Y;

        return listBoxItemBottom > scrollViewerBottom ? Visibility.Hidden : Visibility.Visible;
    }

    public object[] ConvertBack(
        object value,
        Type[] targetTypes,
        object parameter,
        CultureInfo culture) =>
        throw new NotSupportedException();
}

它的声明:

<local:ListBoxItemToVisibilityConverter x:Key="ListBoxItemToVisibility"/>

它在项目模板中的使用:

<DataTemplate>
    <Button Content="{Binding Text}">
        <Button.Visibility>
            <MultiBinding Converter="{StaticResource ListBoxItemToVisibility}">
                <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBoxItem}"/>
                <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ScrollViewer}"/>
                <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBox}"/>
                <Binding Path="ActualHeight" RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBoxItem}"/>
                <Binding Path="VerticalOffset" RelativeSource="{RelativeSource FindAncestor, AncestorType=ScrollViewer}"/>
                <Binding Path="ActualHeight" RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBox}"/>
            </MultiBinding>
        </Button.Visibility>
    </Button>
</DataTemplate>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接