【问题标题】:How can I bind top N items of an ObservableCollection to ItemsControl?如何将 ObservableCollection 的前 N ​​个项目绑定到 ItemsControl?
【发布时间】:2019-08-15 12:59:56
【问题描述】:

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

我试过这个解决方案: Binding to first N items in an ObservableCollection on a ListView

这是我的代码:
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还是没有更新呢?

你能帮帮我吗?谢谢。

【问题讨论】:

  • 现在,您只需设置 ItemsSource 一次。但是您需要在更新实际支持数据后对其进行更新。通常,这是通过Bindings 完成的(您也可以在上面的代码中部分使用它)......理论上可以通过一些附加属性或一些 CollectionViewSource

标签: c# wpf observablecollection


【解决方案1】:

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

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

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

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

【讨论】:

  • 我尝试过并且工作过。然而,我需要将 Window 的 DataContext 绑定到 Window self 所以我不能将它绑定到模型。有没有其他方法可以做到这一点?
  • 使CM成为窗口的公共属性并将ItemsSource绑定到“CM.TopCollection”。
  • 也许我发现了我的问题,我应该将 CM 绑定到 ItemsSource 但不要将其设置为 ItemsSource。
  • 是的,我改变了这样的代码:IC.SetBinding(ItemsControl.ItemsSourceProperty, new Binding { Source = CM });它奏效了。
【解决方案2】:

你的 CollectionModel 是一个 ObservableCollection,你说得对。这意味着它会在添加/删除项目时引发事件(供订阅者观察和采取行动)。

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

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

【讨论】:

  • 但是,即使我替换了 'public IEnumerable TopCollection => this.Take(10);'到'public ObservableCollection TopCollection => new ObservableCollection(this.Take(10));'。还是不行。
  • 是的,@mm8 的改变也是必要的。
  • 同样感谢。
猜你喜欢
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
  • 2012-07-04
  • 2011-11-30
  • 1970-01-01
  • 2017-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多