将ListCollectionView应用于DataGrid而不阻止UI

时间:2017-07-17 10:16:00

标签: c# wpf datagrid

我试图找到一种方法将ListCollectionView应用于WPF中的DataGrid,以便在更新视图时UI保持响应。

DataGrid显示大量数据,必须对其进行分组。目前,我使用ListCollectionView来执行此操作,但在应用ListCollectionView时,UI会锁定,我认为这是必须加载整个数据集从而阻止虚拟化的结果。

我不需要减少加载时间,因为此例程用于报告并且不会经常运行,但是我确实需要阻止UI在应用ListCollectionView时锁定。

我希望ListCollectionView在后​​台线程中应用,而BusyIndicator在网格上显示消息。

目前,网格中的数据填充如下所示:

DataRecord是相关表的名称,也是表示该表中一行的EF对象的名称。

IsBusy是一个bool,它绑定到扩展WPF工具包中IsBusy的{​​{1}}属性,该工具包将BusyIndicator包装在视图中。

DataGrid是一个RecordsList对象,绑定到List<DataRecord>的{​​{1}}属性。

NB。下面显示的代码已被更改,以使其更通用。此片段取自实时项目,并已更改为隐藏客户端数据和身份。

ItemsSource

例程在DataGrid中运行, private void DisplayAllRecords() { IsBusy = true; String sqlConnect = SqlConnectionString; DbConnection connection = EFConnectionFactory.MakeConnection(sqlConnect); List<DataRecord> Batches = new List<DataRecord>(); using (var db = new efContext(connection)) { DbSet<DataRecord> Result = db.DataRecords; foreach (DataRecord dr in Result) { RecordsList.Add(dr); } } ListCollectionView lcv = new ListCollectionView(RecordsList); lcv.GroupDescriptions.Add(new PropertyGroupDescription("authorisedBy")); DataRecordsGridContent = lcv; IsBusy = false; } ViewModel之间的关系使用View中定义的ViewModel创建为View First,如下所示

DataTemplate

在这种形式中,App.xaml将按原样填充,但是启用 <DataTemplate DataType="{x:Type ViewModels:DataRecordViewModel}"> <Views:DataRecordView /> </DataTemplate> 后,由于存在大量行,因此填充网格需要超过30秒的时间,因此它不能延迟加载。

我试图将整个例程放在DataGridListCollectionView中,并在BackgroundWorker上运行,但无济于事。在应用Task之前,UI将被阻止。

通过将Dispatcher的赋值放在后台任务中(使用与整个例程相同的方法),我没有运气。在这种情况下,在呈现ListCollectionView之前,UI根本不显示。

当没有填充数据时,设置ListCollectionView会正确显示ListCollectionView上的加载消息。

期望的结果是UI将加载,窗口将被渲染,IsBusy将显示,直到DataGrid应用于BusyIndicator。完成后,ListCollectionView将被隐藏。

有人可以建议是否可以实现我自己的分组方法吗? 看起来反直觉我需要更改分组方法,以便停止在UI线程上加载DataGrid,从而完全锁定UI。

1 个答案:

答案 0 :(得分:1)

您应该在后台线程上连接并查询数据库,但在UI线程上创建ListCollectionView

private void DisplayAllRecords()
{
    IsBusy = true;
    Task.Factory.StartNew(() =>
    {
        //this code is executed on a background thread
        String sqlConnect = SqlConnectionString;
        DbConnection connection = EFConnectionFactory.MakeConnection(sqlConnect);
        List<DataRecord> Batches = new List<DataRecord>();

        using (var db = new efContext(connection))
        {
            DbSet<DataRecord> Result = db.DataRecords;

            foreach (DataRecord dr in Result)
            {
                RecordsList.Add(dr);
            }
        }
    }).ContinueWith(task =>
    {
        //this code is executed back on the UI thread
        ListCollectionView lcv = new ListCollectionView(RecordsList);
        DataRecordsGridContent = lcv;
        IsBusy = false;
    }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}

如果UI元素的实际呈现速度较慢,而不是检索数据,则应确保在视图中未以某种方式禁用UI虚拟化。

另请注意,使用CollectionView对相当大的PropertyGroupDescription进行分组非常方便且非常灵活但速度很慢。您可能想要考虑自己对集合进行分组,例如使用LINQ,然后在视图中自定义“组”行的外观。