Async/await、调用后更新UI组件、“不同线程拥有它”的异常。

12 浏览
0 Comments

Async/await、调用后更新UI组件、“不同线程拥有它”的异常。

这个问题已经有了答案

因为不同线程拥有该对象,所以调用线程无法访问此对象

我需要将一些网格列附加到仅包含少数列的网格中。创建这些列是长时间运行的,我正在尝试使用async /await,但是出现了“因为不同的线程拥有它,所以调用线程无法访问此对象”的异常,所以有人可以指导我正确的做法吗? 异常发生在AddRange调用上。 预先感谢。

private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    List cols = await NewGridColsAsync();
    viewGridControl.Columns.AddRange(cols);
}
private async Task<List> NewGridColsAsync()
{
    List cols = new List();
    await Task.Run(() =>
    {
        for (int i = 0; i < 100; i++)
        {
            cols.Add(new GridViewColumn());
        }
    });
    return cols;
}

admin 更改状态以发布 2023年5月22日
0
0 Comments

正如其他人指出的那样,必须在UI线程上创建UI对象。由于没有需要CPU执行的工作,因此不需要使用Task.Run

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
  List cols = NewGridCols();
  viewGridControl.Columns.AddRange(cols);
}
private List NewGridCols()
{
  List cols = new List();
  for (int i = 0; i < 100; i++)
  {
    cols.Add(new GridViewColumn());
  }
  return cols;
}

如果您有如此多的UI元素,以至于“无法”在UI线程上运行,则需要实现某种形式的虚拟化。UI线程的速度足以创建比人脑能够处理的UI元素更多;如果您看到有显着的延迟,那么人脑也无法处理那么多的元素,这种情况下正确的答案是使用虚拟化。

0
0 Comments

你正在一个线程上创建GridViewColumn控件实例(由Task.Run创建),并尝试在其他线程(UI线程)上添加它们。由于对象在不同的线程上创建,因此会出现异常。\n\n正确的实现应该类似于以下代码。请注意,控件(GridViewColumn)实例是在UI线程上创建的,因此稍后可以将它们用作主UI线程中其他控件的子控件添加:\n\n

private async Task> NewGridColsAsync()
{
   IEnumerable 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();
}

0