如何将 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还是没有更新呢?
你能帮帮我吗?谢谢。
您需要绑定到 CollectionModel
的 TopCollection
属性 才能使 PropertyChanged
事件生效:
public MainWindow()
{
InitializeComponent();
DataContext = CM;
IC.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("TopCollection"));
}
如果将 DataContext
设置为实现 INotifyPropertyChanged
的 CollectionModel
,则可以在 XAML 标记中执行此操作:
<ItemsControl x:Name="IC" ItemsSource="{Binding TopCollection}" ... />
您的 CollectionModel 是一个 ObservableCollection,您说对了。这意味着它会在项目 added/removed.
时引发事件(供订阅者观察和采取行动)
但是,您实际绑定到的 "TopCollection" 只是一个 IEnumerable。简而言之,它不会引发使其完全数据绑定的事件。
您需要公开 TopCollection 的 ObservableCollection。然后,您可以在其基础数据源发生变化时引发事件,甚至仅在其过滤结果发生变化时引发事件。
我想将 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还是没有更新呢?
你能帮帮我吗?谢谢。
您需要绑定到 CollectionModel
的 TopCollection
属性 才能使 PropertyChanged
事件生效:
public MainWindow()
{
InitializeComponent();
DataContext = CM;
IC.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("TopCollection"));
}
如果将 DataContext
设置为实现 INotifyPropertyChanged
的 CollectionModel
,则可以在 XAML 标记中执行此操作:
<ItemsControl x:Name="IC" ItemsSource="{Binding TopCollection}" ... />
您的 CollectionModel 是一个 ObservableCollection,您说对了。这意味着它会在项目 added/removed.
时引发事件(供订阅者观察和采取行动)但是,您实际绑定到的 "TopCollection" 只是一个 IEnumerable。简而言之,它不会引发使其完全数据绑定的事件。
您需要公开 TopCollection 的 ObservableCollection。然后,您可以在其基础数据源发生变化时引发事件,甚至仅在其过滤结果发生变化时引发事件。