Wpf数据虚拟化

时间:2011-08-17 20:38:54

标签: c# wpf performance data-virtualization

我正在尝试将相当大的项目列表加载到WPF DataGrid中。问题是:这很痛苦。现在我的列表中有大约20,000个项目,它需要永远(好吧......在我的最新版本中需要大约10秒,但这还不够好)。我在最近几天工作,但我找不到真正有用的解决方案。

1)当然启用了UI虚拟化(这不再是问题)

2)我也尝试了Bea Stollnitz here和其他人所描述的一些解决方案。这些解决方案很棒,但对我来说不起作用,因为我的集合必须在运行时更新,过滤和排序,而无需重新加载集合。我找到的解决方案只适用于IList实现......我需要一个Observable集合来保持我的项目是最新的。

情况就是这样:我确实有一个Observable我的域数据对象集合(它通过WCF更新了)。我有一个ViewModel用于包装域对象的列表项。当我打开视图时,我有第二个列表,将为每个域对象填充ViewModel实例。这是真正的问题。由于“target”集合绑定到我的DataGrid,我必须将ViewModel的创建分配到UI线程中(否则.Net对来自另一个线程的集合更改不是很满意)。所以我用20,000个视图模型创建调用来污染Dispatcher队列。创建一个ViewModel非常便宜,但我仍然在调度程序队列中有20,000个调用,同时DataGrid要求同一个线程中的CPU来填充自己。

我的想法(还没有完成):由于我已经有了UI虚拟化,我想在打开视图时创建ViewModels NOT,但在运行中我需要它们。当用户最初可以看到前20个条目时,我只需要创建20个ViewModel而不是20,000个。这是我的问题:我不知道如何。那就是你进来的地方:)

我想有这样的事情(不是那样工作......只是为了表明我的意思):

<DataGrid ItemsSource={Binding MyDomainOjectCollection}>
    <DataGrid.RowStyle>
        <Style>
            <Setter Property="DataContext" 
                    Value="{Binding DataContext, 
                            Converter={StaticResource  MyViewModelFactoryConverter}}">
            </Setter>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

它不一定是转换器,它也可以是其他东西或在后面的代码中完成。我不在乎。我需要的是:直接绑定到DomainObject集合,动态创建相应的ViewModel并使用刚刚创建的ViewModel而不是原始对象来填充单行。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我认为,淹没你的ObservableCollection并为每个项目更新UI是个问题。

您应该使用BindingList。您可以在添加一系列项目时禁用其上的事件,如下所示:

BindingList.RaiseListChangedEvents = false;

将阻止UI接收任何事件。然后在批量添加后,您可以使用以下命令启用它:

BindingList.RaiseListChangedEvents = true;
BindingList.ResetBindings();

答案 1 :(得分:0)

  

当我打开视图时,我有第二个列表,将为每个域对象填充一个ViewModel实例。

好,那应该是你过滤的ObservableCollection。

  

由于“target”集合绑定到我的DataGrid,我必须将ViewModel的创建分配到UI线程

不,你不。 ViewModel是一个非UI元素,它可以在任何线程上创建。它是将这些项添加到需要在UI线程上完成的ObservableCollection中。因此,您可以在任何地方创建所有VM包装器,我建议您批量执行,然后将批处理填充到ObservableCollection中作为一个操作。现在我知道ObservableCollection被设置为一次只添加一个项目,但通过向其添加扩展方法可以很容易地解决这个问题,如this previous SO answer中所示。请注意,您只需在UI线程上调用扩展方法,一旦您可以逐个添加项目。

就个人而言,我会疯狂地战斗,不能一直检索所有数据,我认为你已经分析了这个要求而无法避免它。但是你真的需要在客户端进行过滤和排序吗?这可以通过向服务器发送数据来实现,然后服务器回复相应的数据吗?

在任何情况下,如果你必须获得所有数据,那么我建议你分批进行(虽然20K项目不是很大,但仍然是合理的)。这可以非常轻松地完成,并且在您的viewmodel中使用属性通知,您可以使用已添加到源集合中的内容使过滤的集合保持最新。