Async/await,调用后更新ui组件,“不同线程拥有它”;例外
本文关键字:拥有 线程 例外 组件 调用 await 更新 Async ui | 更新日期: 2023-09-27 18:02:57
我需要将一些网格列附加到最初仅包含几列的网格中。创建列是长期运行的,我试图使用async/await,但我得到"调用线程不能访问这个对象,因为不同的线程拥有它"异常,所以有人可以指导我正确的方法来做到这一点。异常发生在adrange调用上。提前谢谢。
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
List<GridViewColumn> cols = await NewGridColsAsync();
viewGridControl.Columns.AddRange(cols);
}
private async Task<List<GridViewColumn>> NewGridColsAsync()
{
List<GridViewColumn> cols = new List<GridViewColumn>();
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
cols.Add(new GridViewColumn());
}
});
return cols;
}
您正在一个线程(由Task.Run
创建)上创建GridViewColumn
控件实例,并试图将它们添加到其他线程(UI线程)上。因为对象是在不同的线程上创建的,所以你会得到这个异常。
正确的实现应该类似于下面的代码。请注意,控件(GridViewColumn
的实例)是用这段代码在UI线程上创建的,以后可以用来从主UI线程添加其他控件的子控件:
private async Task<List<GridViewColumn>> NewGridColsAsync()
{
IEnumerable<DataForColumn> dataForColumns;
await Task.Run(() =>
{
// collect data for columns, runs on thread-pool (non-UI) thread
dataForColumns = ....
});
// runs on UI thread
return dataForColumns.Select(data => CreateGridViewColumn(data)).ToList();
}
正如其他人所指出的,您必须在UI线程上创建UI对象。因为没有cpu限制的工作要做,所以不需要Task.Run
:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
List<GridViewColumn> cols = NewGridCols();
viewGridControl.Columns.AddRange(cols);
}
private List<GridViewColumn> NewGridCols()
{
List<GridViewColumn> cols = new List<GridViewColumn>();
for (int i = 0; i < 100; i++)
{
cols.Add(new GridViewColumn());
}
return cols;
}
如果你有太多 UI元素,这些元素"不能"放在UI线程上,那么你就需要实现某种形式的虚拟化。UI线程足够快,可以创建比人脑处理能力更多的UI元素;如果您看到明显的延迟,那么人类的大脑无论如何都无法处理那么多元素,正确的答案是使用虚拟化。