我们正在设计一个桌面应用程序,它在某个时刻显示 10.000-100.000 个项目的列表。我们使用
DataGrid
绑定到 ObserableCollection
问题是,有时您需要一次操作向该集合添加或删除最多 100.000 个项目。 ObservableCollection
允许这样做的唯一方法是通过 Add
和 Remove
,一次执行一项。这是非常低效的并且需要很长时间,因为每个 Add
都会触发一个 NotifyCollectionChangedEvent
,从而触发很多东西。
我一直在研究对
ObservableCollection
的批量更新支持:NotifyCollectionChangedEventArgs
有一个可以接受IList
的构造函数,但是ObservableCollection
现在不提供使用它的方法。显然它被添加到 corefx,但在新版本的 .NET 中又被删除了?
曾尝试将其添加到 .NET,但所有 PR 都被拒绝,因为他们仍然想考虑 API。例如。 这个.
我尝试的是将 PR 的源代码复制到我的本地项目并将其绑定到我们的
DataGrid
。但它似乎不起作用:当我使用批量插入添加项目时,视图不会更新:这是因为我使用了 new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, itemsAdded, startingIndex)
。
当我想要批量删除集合中不同位置的项目并通过
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, itemsRemoved)
时,情况会变得更糟:我收到带有无效索引的 WinRT 异常,导致应用程序崩溃。可能是因为构造函数的重载将 -1
作为起始索引而引起。
看起来
DataGrid
就是不支持这个,还是不支持?我一直在四处寻找有关该主题的任何信息,但似乎找不到。由于微软几乎不支持 WinUI-3(相信我,过去几年我尝试在他们的 github 上报告几个错误,但很少得到答案),我不指望从他们那里得到任何帮助,除了:“没有计划”或“积压”。我也无法在堆栈溢出中找到任何尝试过此操作的人。
有人尝试过并找到解决方案吗?有人知道尝试过这个的人吗?有人在 WinUI-3 上工作吗?
附注我一直在考虑发送一个像
here建议的
NotifyCollectionChangedAction.Reset
,但这对应用程序的其余部分不起作用:它不提供带有添加和删除项目的OnCollectionChanged
事件处理程序,所以很多东西,比如取消订阅已删除项目中的事件处理程序,或解除父级的附加,都不会被触发:这会导致内存泄漏(因为已删除的项目无法被GCed),甚至例外(因为删除的项目仍在处理事件)。
GitHub 上有一个关于 AddRange
的
讨论
ObservableCollection
,但不幸的是,暂时没有任何进展。
您可以尝试的是自己添加
AddRage
支持。像这样的东西:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollectionExSampleApp;
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
private readonly static System.ComponentModel.PropertyChangedEventArgs ItemsINPC = new System.ComponentModel.PropertyChangedEventArgs("Item[]");
private readonly static System.ComponentModel.PropertyChangedEventArgs CountINPC = new System.ComponentModel.PropertyChangedEventArgs(nameof(Count));
public void AddRange(IEnumerable<T> collection)
{
CheckReentrancy();
int count = 0;
foreach (var item in collection)
{
count++;
base.Items.Add(item); // Editing this protected list won't raise events
}
if(count > 0)
{
OnPropertyChanged(ItemsINPC);
OnPropertyChanged(CountINPC);
if (count > 1) // Multi-item change
{
OnCollectionChanged(
new NotifyCollectionChangedEventArgs(
action: NotifyCollectionChangedAction.Add,
changedItems: collection as System.Collections.IList ?? collection.ToList(),
startingIndex: Count - count));
}
else // count == 1 - single-item change
{
OnCollectionChanged(
new NotifyCollectionChangedEventArgs(
action: NotifyCollectionChangedAction.Add,
changedItem: collection.First(),
index: Count - 1));
}
}
}
}
如果您想观看它的实际效果,请在我的 YouTube 频道上观看视频。