如何将 ObservableCollection 的前 N ​​项绑定到 ItemsControl?

How can I bind top N items of an ObservableCollection to ItemsControl?

我想将 ObservableCollection 的前 N ​​项绑定到 ItemsControl。

我试过这个解决方案:

这是我的代码:
XAML:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <ItemsControl x:Name="IC" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="#cecece" BorderThickness="0,0,0,1" Background="Transparent" >
                        <TextBlock Text="{Binding ABC}"></TextBlock>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel></VirtualizingStackPanel>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <Button Grid.Column="1" Click="Button_Click"></Button>
    </Grid>
</Window>

代码隐藏:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            IC.ItemsSource = CM.TopCollection;
        }
        CollectionModel CM = new CollectionModel();
        public class TestModel {
            public string ABC { get; set; }
        }
        public class CollectionModel : ObservableCollection<TestModel>, INotifyPropertyChanged
        {
            public CollectionModel()
            {
                CollectionChanged += MyCollection_CollectionChanged;
            }          

            private void MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {   // to notify XAML-side binding
                OnPropertyChanged(new PropertyChangedEventArgs(nameof(TopCollection)));
            }
            public IEnumerable<TestModel> TopCollection => this.Take(10);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            CM.Add(new TestModel() {ABC= Guid.NewGuid().ToString() });
        }
    }
}

我点击了按钮。但是,CM 添加新项目成功,但 UI 没有更新任何项目。

为什么会变成这样?

我打断点测试,发现CollectionChanged&OnPropertyChanged都可以。但是为什么UI还是没有更新呢?

你能帮帮我吗?谢谢。

您需要绑定到 CollectionModelTopCollection 属性 才能使 PropertyChanged 事件生效:

public MainWindow()
{
    InitializeComponent();
    DataContext = CM;
    IC.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("TopCollection"));
}

如果将 DataContext 设置为实现 INotifyPropertyChangedCollectionModel,则可以在 XAML 标记中执行此操作:

<ItemsControl x:Name="IC" ItemsSource="{Binding TopCollection}" ... />

您的 CollectionModel 是一个 ObservableCollection,您说对了。这意味着它会在项目 added/removed.

时引发事件(供订阅者观察和采取行动)

但是,您实际绑定到的 "TopCollection" 只是一个 IEnumerable。简而言之,它不会引发使其完全数据绑定的事件。

您需要公开 TopCollection 的 ObservableCollection。然后,您可以在其基础数据源发生变化时引发事件,甚至仅在其过滤结果发生变化时引发事件。