【问题标题】:adding more items to NavigationView takes to long向 NavigationView 添加更多项目需要很长时间
【发布时间】:2021-01-03 11:46:17
【问题描述】:

我想向 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 需要很长时间

【问题讨论】:

  • 我以前也遇到过类似的问题,这是因为 UI 试图渲染这些项目,即使它们不在视图中。如果我记得,我的解决方案是设置一个标志,以不尝试渲染实际上不在屏幕中的项目。或者我不得不使用不同的控件。记不清了,但问题是 UI 实际上是在尝试绘制所有正在添加的项目,而且这似乎也是你的问题。

标签: c# uwp navigationview


【解决方案1】:

这个过程很慢,因为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));
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-27
    • 2014-05-06
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多