我试图找到一种方法将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秒的时间,因此它不能延迟加载。
我试图将整个例程放在DataGrid
,ListCollectionView
中,并在BackgroundWorker
上运行,但无济于事。在应用Task
之前,UI将被阻止。
通过将Dispatcher
的赋值放在后台任务中(使用与整个例程相同的方法),我没有运气。在这种情况下,在呈现ListCollectionView
之前,UI根本不显示。
当没有填充数据时,设置ListCollectionView
会正确显示ListCollectionView
上的加载消息。
期望的结果是UI将加载,窗口将被渲染,IsBusy
将显示,直到DataGrid
应用于BusyIndicator
。完成后,ListCollectionView
将被隐藏。
有人可以建议是否可以实现我自己的分组方法吗?
看起来反直觉我需要更改分组方法,以便停止在UI线程上加载DataGrid
,从而完全锁定UI。
答案 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,然后在视图中自定义“组”行的外观。