WPF ListBox的高度可以设置为其项目高度的倍数吗?

时间:2012-02-28 05:45:29

标签: wpf listbox

是否有某种方法可以将WPF多选Height的{​​{1}}属性设置为项高度的倍数,类似于设置html的ListBox属性{ {1}}元素?

我有一个业务要求有半个项目显示在列表的底部(如果它是一个带有滚动条的长列表),并且底部没有额外的空白区域(如果这是一个显示所有项目的简短列表),但我能找到的唯一方法就是不断调整size直到看起来正确。

(我还尝试了什么?我曾经问同事,搜索过MSDN和StackOverflow,做了一些普通的Google搜索,看看VS Intellisense在编辑代码时提供了什么。有很多关于如何设置的建议高度以适应ListBox的容器,但这与我正在尝试的相反。)

2 个答案:

答案 0 :(得分:7)

是的,可以想象会有一种更简单的方法(单个snapToWholeElement属性)。我也找不到这个属性。

为了达到你的要求,我写了一点逻辑。基本上,在我的Windows对象中,我有一个公共属性 lbHeight ,它通过计算每个项目的高度来计算列表框高度。

首先,让我们来看看XAML:

<Window
    x:Class="SO.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="120" SizeToContent="Height"
    Title="SO Sample"    
    >
    <StackPanel>
        <ListBox x:Name="x_list" Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=lbHeight}" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border x:Name="x" Background="Gray" Margin="4" Padding="3">
                        <TextBlock Text="{Binding}" />
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>        
</Window>

请注意,ItemTemplate有点不重要。需要注意的一件重要事情是,我给这个项目命名 - 所以我可以在以后找到它。

在代码隐藏构造函数中,我将一些数据放在列表框中:

public MainWindow( )
{
    InitializeComponent( );
    this.x_list.ItemsSource = Enumerable.Range( 0, 100 );
}

接下来,我正在实现一个findVisualItem - 来查找数据模板的根元素。我已经使这个函数变得有点泛,所以它得到一个谓词 p ,它确定这是否是我想要找到的元素:

private DependencyObject findVisualItem( DependencyObject el, Predicate<DependencyObject> p )
{
    DependencyObject found = null;

    if( p(el) ) {
        found = el;
    }
    else {
        int count = VisualTreeHelper.GetChildrenCount( el );
        for( int i=0; i<count; ++i ) {
            DependencyObject c = VisualTreeHelper.GetChild( el, i );
            found = findVisualItem( c, p );
            if( found != null )
                break;
        }
    }
    return found;
}

我将使用以下谓词,如果我正在查找的元素是边框,并且其名称为“x”,则返回true。您应该修改此谓词以匹配ItemTemplate的根元素。

findVisualItem(
    x_list,
    el => { return ( el is Border ) ? ( (FrameworkElement)el ).Name == "x" : false; }
    );

最后,lbHeight属性:

public double lbHeight
{
    get {
        FrameworkElement item = findVisualItem( 
            x_list,
            el => { return ( el is Border ) ? ( (FrameworkElement)el ).Name == "x" : false; }
            ) as FrameworkElement;
        if( item != null ) {
            double h = item.ActualHeight + item.Margin.Top + item.Margin.Bottom;
            return h * 12;
        }
        else {
            return 120;
        }
    }
}

我还使Window实现了INotifyPropertyChanged,当列表框的项目被加载时(ListBox的Loaded事件),我为'lbHeight'属性触发了一个PropertyChanged事件。在某些时候它是必要的,但最后WPF在我已经有一个渲染的项目时获取了lbHeight属性。

您的项目在高度上可能不相同,在这种情况下,您必须将VirtualizedStackPanel中的所有项目相加。如果你有一个水平滚动条,你必须考虑它的总高度当然。但这是整体想法。你发表问题只有3个小时 - 我希望有人会得到一个更简单的答案。

答案 1 :(得分:1)

这是通过将父控件Height属性设置为Auto来完成的,而无需为列表框本身设置任何大小(或者还设置为自动)。 要限制列表大小,您还应指定MaxHeight属性