如果我使用ActionBlock
进行数据库调用,并且需要更新GUI(可能是ObservableCollection
)。循环遍历结果集并使用Dispatcher.BeingInvoke
一个好的解决方案,还是有更好的方法?
我想一次一行地加载到GUI,因为即使启用了虚拟化,似乎我立即更新整个可观察集合,GUI会挂起,直到它可以呈现整个数据网格。
一些模拟情况的示例代码:
ActionBlock<Func<Task>> _block = new ActionBlock<Func<Task>>(action => action());
_block.Post(async () =>
{
await Task.Delay(1000); // Perhaps Long database read
for (int i = 0; i < 1000000; i++) // Perhaps looping over database result set
{
await Dispatcher.BeginInvoke( // Need to update GUI
new Action(
() =>
{
// Add new object to collection (GUI will update DataGrid one row at a time).
MyModel.MyCollection.Add(new MyClass() { MyInt = i });
}
), DispatcherPriority.Background
);
}
});
答案 0 :(得分:1)
如果你在循环中添加调用Dispather.BeginInvoke,那么你将更新UI 100k次。理想情况下我会这样做:
//do as much work as possible in background thread
var items = new MyClass[100000];
for (int i = 0; i < 1000000; i++) {
items[i] = new MyClass{ MyInt = i;}
}
Dispatcher.BeginInvoke(new Action(() => //update UI just once
MyModel.MyCollection = new ObservableCollection(items);
));
如果您的虚拟化确实有效,那应该没问题。
为了避免在UI线程中添加大量数字,您可以将其拆分为较小的数据部分:
for (int i = 0; i < 100; i++){
await Dispatcher.BeginInvokenew Action(() =>
{
for (int j = 0; j < 1000; j++) { //add thousand items at once
MyModel.MyCollection.Add(items[i * 1000 + j])
});
}
答案 1 :(得分:0)
循环遍历结果集并使用Dispatcher.BeingInvoke是一个很好的解决方案,还是有更好的方法?
在现代应用程序中使用Dispatcher.BeginInvoke
从来没有充分的理由。
在您的情况下,由于您已经在使用TPL数据流,因此您只需将ActionBlock
更改为TransformManyBlock
,并将其链接到在UI上执行的单独ActionBlock
线。类似的东西:
var _getRowsBlock = new TransformManyBlock<Func<Task<IEnumerable<TRow>>>, TRow>(
action => action());
var _updateUiBlock = new ActionBlock<TRow>(row =>
{
MyModel.MyCollection.Add(new MyClass() { MyInt = i });
}, new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(),
});
_getRowsBlock.LinkTo(_updateUiBlock, new DataflowLinkOptions { PropagateCompletion = true });
_block.Post(async () =>
{
await Task.Delay(1000); // Perhaps Long database read
return result.Rows; // return the database result set
});
我想一次一行地加载到GUI,因为即使启用了虚拟化,似乎我立即更新整个可观察集合,GUI会挂起,直到它可以呈现整个数据网格。
那么,你可能正在寻找错误的解决方案。我不知道如何一次添加一行数据会有所帮助。如果用户手工操作系统一次性添加1000000行,那么一次添加一行1000000行会更加严重......
您可能必须考虑一个解决方案,其中不将1000000行加载到您的UI中。