通过ViewModel中的属性MaxNumberOfVisibleItems在ListBox中显示项目?

时间:2015-05-26 09:23:17

标签: wpf

我使用MVVM模式。在ViewModel中有属性MaxVisibleItems。 在视图中:

<ListBox ItemsSource="{Binding Items}" Margin="0 0 0 5"
     VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsContainerVirtualizable="True">
   <ListBox.ItemsPanel>
       <ItemsPanelTemplate>
          <VirtualizingStackPanel/>
       </ItemsPanelTemplate>
    </ListBox.ItemsPanel>

 如何通过ViewModel中的MaxVisibleItems计算ListBox中可见项的数量。这意味着如果有10个项目且MaxVisibleItems为8,则只显示8个项目,并且滚动条滚动到其他项目。这意味着,MaxVisibleItems设置显示项目的控件的最大高度。 谢谢你的帮助!!!

3 个答案:

答案 0 :(得分:0)

这是一个非常疯狂的解决方案:

创建一个接口和一个继承自ObservableCollection的新类,这将允许我们使用转换器计算出应显示的项目数。

public interface ILimitedCollection : IList
{
    int MaxViewable { get; set; }
}

public class LimitedObservableCollection<T> : ObservableCollection<T>, ILimitedCollection
{
    private int _MaxViewable;

    public int MaxViewable
    {
        get { return _MaxViewable; }
        set 
        { 
            _MaxViewable = value; 

            OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("MaxViewable"));
        }
    }
}

您的馆藏应该继承LimitedObservableCollection,而不是ObservableCollection,然后您可以使用以下转化器:

public class LimitedListConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ILimitedCollection collection = (ILimitedCollection)value;

        ObservableCollection<object> items = new ObservableCollection<object>();

        for (int i = 0; i < collection.MaxViewable; i++)
        {
            var item = collection[i];

            items.Add(item);
        }

        return items;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这只会限制要在集合中显示的项目数。

用法:

{Binding YourCollection, Converter={StaticResource LimitedListConverter}}

备注

您可能想知道为什么我不只是使用ConverterParameter。好吧,我可以,但是不可能将ConverterParameter绑定到ViewModel中的属性。因此,更复杂的解决方案就足够了。

这可能不是最佳解决方案,但是,它肯定是一个开始。

答案 1 :(得分:0)

鉴于您知道物品的固定高度,您可以使用以下内容:

public class FixedHeightConverter : IValueConverter
{
    // Change to whatever your fixed height is.
    const int ItemHeight = 25;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // Note that this currently will display the ListBox with a height of 0 when there are no entries. It would probably be sensible to make use of the MinHeight property in xaml or factor in a MinHeight property in this code.
        if (value is int)
        {
            return ((int)value) * ItemHeight;
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is int)
        {
            return ((int)value) / ItemHeight;
        }

        return value;
    }
}

您的ListBox需要更改为:

<ListBox ItemsSource="{Binding Items}" Margin="0 0 0 5"
         Height="{Binding MaxVisibleItems, Converter={StaticResource FixedHeightConverter}}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

请注意,如果您想在UI的其他部分重复使用它,并且您有不同的固定高度,那么您可以考虑将ItemHeight设为属性而不是const。

答案 2 :(得分:0)

由于您的商品具有固定的高度,我建议您以这种方式扩展ListBox控件:

namespace WpfApplication1
{
    public class ListBox : System.Windows.Controls.ListBox
    {
        public ListBox()
        {
            Loaded += new RoutedEventHandler(OnLoaded);
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (MaxVisibleItemsCount < Int32.MaxValue)
            {
                MaxHeight = (ActualHeight / Items.Count) * MaxVisibleItemsCount;
            }
        }

        public int MaxVisibleItemsCount
        {
            get { return (int)GetValue(MaxVisibleItemsCountProperty); }
            set { SetValue(MaxVisibleItemsCountProperty, value); }
        }

        public static readonly DependencyProperty MaxVisibleItemsCountProperty =
            DependencyProperty.Register("MaxVisibleItemsCount", typeof(int), typeof(ItemsControl), new UIPropertyMetadata(Int32.MaxValue));
    }
}

然后你的XAML将是:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="Window1" Height="300" Width="300">
    <Window.Resources />

    <DockPanel>
        <local:ListBox Margin="5" DockPanel.Dock="Top"
                       MaxVisibleItemsCount="5"
                       VirtualizingStackPanel.VirtualizationMode="Recycling"
                       VirtualizingStackPanel.IsVirtualizing="True">
            <local:ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                </ItemsPanelTemplate>
            </local:ListBox.ItemsPanel>
            <local:ListBox.Items>
                <sys:String>One</sys:String>
                <sys:String>Two</sys:String>
                <sys:String>Three</sys:String>
                <sys:String>Four</sys:String>
                <sys:String>Five</sys:String>
                <sys:String>Six</sys:String>
                <sys:String>Seven</sys:String>
                <sys:String>Eight</sys:String>
                <sys:String>Nine</sys:String>
                <sys:String>Ten</sys:String>
            </local:ListBox.Items>
        </local:ListBox>

        <Grid />
    </DockPanel>
</Window>

我用Grid来填补余下的空间。如果没有此Grid,ListBox将扩展其高度以填充窗口中的可用空间。