【问题标题】:WPF UI freezing when loading data into DatagGrid将数据加载到 DatagGrid 时 WPF UI 冻结
【发布时间】:2019-02-02 06:14:39
【问题描述】:

异步数据加载和整个过程 UI 都是响应式的。但是当这条线InvoiceGrid.ItemsSource = results; 执行时,UI 会冻结一秒或更长时间,具体取决于数据的大小。有没有办法摆脱这个 UI 冻结?

private async void FetchInvoicesDataFunc(object sender, RoutedEventArgs  e)

 {
   List<Invoice> results = new List<Invoice>();
   ProgressBtn.Content = "Loading Data ...";
   await Task.Run(async() => results.AddRange(await FetchInvoiceDataAsync(0, 500));  
   ProgressBtn.Content = "25% done...";
   await Task.Run(async() => results.AddRange(await FetchInvoiceDataAsync(501, 1000)); 
   ProgressBtn.Content = "50% done...";
   await Task.Run(async() => results.AddRange(await FetchInvoiceDataAsync(1001, 1500)); 
   ProgressBtn.Content = "75% done...";
   await Task.Run(async() => results.AddRange(await FetchInvoiceDataAsync(1501, 2000));        
   InvoiceGrid.ItemsSource = results;
   ProgressBtn.Content = "Loaded !";    
 }

 private async Task<List<Invoice>> FetchInvoiceDataAsync(int start, int end)
 {
   List<Invoice> result;
   using(var context = new Intelliventory_DBEntities() )
   {  
     result  = await context.Invoices.Where(b => b.InvoiceID >= start && b.InvoiceID <= end).Include(x => x.Customer).ToListAsync();      
   }

   return  result;
 }

【问题讨论】:

  • 是的。加载更少的数据。如果它冻结,则可能是因为您试图显示太多数据。使用分页或某种动态加载。没有人需要同时查看数以万计的记录。另外,永远不要写await Task.Run(async () =&gt; ...)。写await results.AddRange(await FetchInvoiceDataAsync(1501, 2000);
  • 我知道我正在使用分页,但至少应该显示 100 行,它仍然会冻结一小段时间,我认为这很糟糕!
  • 我认为 wpf 的 DataGrid 没有任何用于动态加载的内置选项。您可能想寻找其他一些支持动态加载的控件。也许写一个自定义的。
  • 感谢先生的建议!即使上面的代码我也很难理解!
  • @FCin 写入 await results.AddRange(await FetchInvoiceDataAsync(1501, 2000); 将不起作用,因为 AddRange 不会返回 Task。如果他想将他的结果添加到 GUI 线程之外的列表中,那么解决方案就可以了。

标签: c# wpf async-await wpfdatagrid


【解决方案1】:

它冻结是因为您尝试更新 ProgressBtn,这是来自您的异步方法的 UI 控件。不确定您是否从后台线程调用此方法。如果我要这样做,我会在 FetchInvoiceDataAsync() 方法中引入一个回调来更新 ProgressBtn 控件。在那个回调方法中,我会调用调度程序来更新 UI。这应该可以解决所有冻结问题。

Application.Current.Dispatcher.Invoke(() =>
 {
      // Set property or change UI compomponents.              
 }); 

除此之外,我还建议使用 ListCollectionView 而不是可观察的集合。这将确保您可以在每次向列表添加新内容时调用 refresh 来更新 UI。 希望这会有所帮助!

【讨论】:

  • 任何投反对票的人都会很高兴知道为什么。至少给了我一个改进的机会
  • 因为你的陈述是错误的。如果他从回调线程更改 UI 元素,他会得到一个异常。当他成功更新他的 UI 时,正确的调度程序已经调用了更改 UI 元素的调用。此外,“它冻结是因为您更新了按钮......从您的异步方法”的说法也不正确。使用 async 方法标记的方法会执行非等待调用,就像非异步方法一样。异步和非异步方法之间的唯一区别是您可以在异步方法中等待其他异步方法调用
  • @Dominik 我想说的是,他应该调用一个长处理方法并传递一个 UI 回调方法,该方法应该在每次达到一定范围以更新进度条时调用。除此之外,当您必须在批量获取内容时频繁更新 UI 时,使用 ListCollectionView 总是有帮助的。关于异步方法,不清楚是从 UI 线程还是某个后台线程调用。
猜你喜欢
  • 2016-07-30
  • 2021-11-15
  • 2015-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多