WPF数据表格的惰性加载

8

细节

  1. VS-2008专业版SP1
  2. 版本.net 3.5
  3. 语言:C#

我有一个WPF数据网格,它从Linq-sql查询Datacontext数据项加载。结果集包含约200k行,加载,排序,过滤等非常缓慢。 有什么简单易行的方法来提高速度吗?

我在搜索中看到了几件事情 滚动视图,数据虚拟化等人们也谈论分页,分析等


UI当前是否未虚拟化(我相信默认情况下DataGrid的行是虚拟化的,除非您在DataGrid中使用分组)。但是,由于您指出排序和过滤很慢...问题可能是您已经采取了某些措施停止了行的虚拟化。 - Scott
6个回答

4
加载数据:200k行数据对于用户来说太多了,没有人希望在一个地方看到它们。这肯定会降低您的UI用户体验。所以您最好是过滤您的数据,只减少它的数量(例如不显示已关闭的订单,只显示打开的订单)。如果您无法这样做,您应该使用Virtualization。我没有看到任何应用程序使用分页来显示数据(当然除了web)。大多数情况下这并不是一种好方法。但如果你谈论的是像搜索引擎结果一样的数据类型,你必须使用它。但请记住,大多数用户不会超过搜索引擎结果的第10页。 过滤:对于那么多的数据(在这里是SQL Server),我建议您在服务器端进行过滤或者首先过滤整个200k以减少服务器端的数量,然后在客户端(为了找到某些东西)过滤它(为用户)。您可能还会发现以下链接有帮助:
  1. http://www.codeproject.com/KB/WPF/DataGridFilterLibrary.aspx
排序:同样,我建议使用服务器-客户端解决方案,但您也可能会发现以下链接有帮助:
  1. http://blogs.msdn.com/b/jgoldb/archive/2008/08/26/improving-microsoft-datagrid-ctp-sorting-performance.aspx
  2. http://blogs.msdn.com/b/jgoldb/archive/2008/08/28/improving-microsoft-datagrid-ctp-sorting-performance-part-2.aspx
  3. http://blogs.msdn.com/b/jgoldb/archive/2008/10/30/improving-microsoft-datagrid-sorting-performance-part-3.aspx
许多人不使用WPF datagrid的默认 SortMemberPath ,只因为它在每个记录上都使用反射,这将严重降低排序过程的性能。
Hosein

1
这是一个非常好的数据虚拟化示例(不是 UI 虚拟化):

http://www.codeproject.com/KB/WPF/WpfDataVirtualization.aspx

尽管它不能直接支持 LINQ IQueryable 对象,但您可以直接使用此示例。当然,我现在正在努力将其改进为直接与 IQueryable 对象一起使用。我觉得这并不难。

这是一个派生的VirtualizatingCollection的好例子,可以异步执行加载。谢谢! - NoWar

0
有时您可能只需要加载大约30个可见行,如果这些行+由于它们的数量和每个单元格的复杂性而昂贵的任何列(它的模板或者它包含多少个wpf元素),那么上面的任何评论都不会起作用。每一行将花费很长时间来加载!
有帮助的是在UI上分批或惰性地加载每行,以便用户看到UI正在做某些事情,而不仅仅是冻结约10秒钟以上。
为简单起见,假设datagrid ItemSource =“{Binding Rows}”,Rows是IEnumerable,其中Row是您创建的某个类:向Row添加IsVisible属性(当然不要忘记引发属性更改)
您可以像这样做:
private void OnFirstTimeLoad()
{
    Task.Factory.StartNew(() =>
    {
        foreach (var row in ViewModel.Rows)                                                
        {
            /*this is all you really need, 
              note: since you're on the background thread, make sure IsVisible executes on the UI thread, my utils method does just that*/
              myUtils.ExecuteOnUiThread(() => row.IsVisible = true);

              /*optional tweak: 
              this just forces Ui to refresh so each row repaint staggers nicely*/
              Application.Current.Dispatcher
                         .Invoke(DispatcherPriority.Background, (SendOrPostCallback) delegate { }, null);
         }
       });
}

哦,别忘了在XAML中触发:

<DataGrid.ItemContainerStyle>
    <Style TargetType="{x:Type DataGridRow}">
        <Setter Property="Visibility" Value="{Binding Path=IsVisible, Converter={StaticResource BoolToVisibility}}"/>
      ........

另一个选项是添加简单的淡入效果:将不透明度设置为0.0,然后为包括简单DoubleAnimation的数据网格行的样式添加OnLoad事件触发器。 - dansan

0

哇,20万行数据真的很多。分页听起来是个好主意。尝试决定每页要显示多少行,比如说50行。第一次展示屏幕时,只显示前50行。然后给用户在页面之间移动的选项。

不过这种方式可能会让排序变得更加棘手。

虚拟化可能是另一个选择,但遗憾的是,我还没有使用过虚拟化。


你能提供一些关于分页思想的好阅读材料链接吗? - Ravi Yenugu
抱歉,我没有分页代码的好阅读材料。您已经拥有包含所有项目的完整列表。您可以再创建一个列表,最多包含10个项目。您要做的是向用户显示第二个列表,而不是完整列表。给用户一个上一页和下一页的按钮,并设置一个指针索引指向正在显示的第一项。下一页将向索引添加10,重新创建第二个列表,并刷新显示。 - Efren

0
你的数据网格是否在滚动视图中?因为它会渲染整个数据网格(所有行)。我曾经遇到过类似的问题,移除滚动视图后,慢加载的问题得到了解决。

-1
你应该问的问题是:
  1. 用户是否需要查看 200K 行数据?
  2. 多少数据对于用户来说太多了? 可能需要向用户发出警报,说明查询返回了太多行,并列出前 1000 行。
  3. 如果用户不会查看超过前 1000 行,那么编写分页、数据虚拟化等程序是否值得你的时间和金钱。

1
这可能应该是一个注释? - Josh Noe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接