向 NavigationView 添加更多项目需要很长时间

adding more items to NavigationView takes to long

我想向 NavigationView 添加 1500 个项目 我使用了 actionblock 但它仍然很慢并且在 ui

中添加项目需要大约 10 秒
private ObservableCollection<NavigationViewItem> data;
TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
private void DoSomethingWithCustomer(NavigationViewItem c)
        {

            Task.Run(() =>
            {
                data.Add(c);
            }).ContinueWith(x =>
            {
                NavigationView.MenuItemsSource = data;
            }, taskScheduler);
        }

和:

ActionBlock<NavigationViewItem> action = new ActionBlock<NavigationViewItem>(DoSomethingWithCustomer, new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            });
            var coll = System.IO.Directory.EnumerateDirectories("D:\Pic\Art");
            foreach (var customer in coll)
            {
                var item = new NavigationViewItem { Content = new DirectoryInfo(customer).Name };

                action.Post(item);
            }
            action.Complete();
            await action.Completion;

我试过了,EnumerateDirectories 不到 1 秒就完成了但是向 ui

添加项目需要很长时间

进程很慢,因为 ObservableCollection 实现了 INotifyCollectionChanged 接口,该接口有一个名为 CollectionChanged 的事件。每次将项目添加到集合中并且 UI (NavigationView) 正在侦听它时都会触发此事件。

这意味着每次添加一个项目时,UI 都必须渲染它,这使得添加数百或数千个项目的过程变慢。

您最好的选择是实施您自己的 ObservableCollection 版本,它会延迟触发该事件,直到添加完所有项目。可以在这里找到一个例子:https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/

public class RangeObservableCollection<T> : ObservableCollection<T>
{
  private bool _suppressNotification = false;
 
  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
  {
    if (!_suppressNotification)
      base.OnCollectionChanged(e);
  }
 
  public void AddRange(IEnumerable<T> list)
  {
    if (list == null)
      throw new ArgumentNullException("list");
 
    _suppressNotification = true;
 
    foreach (T item in list)
    {
      Add(item);
    }
    _suppressNotification = false;
    OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  }
}