调用线程无法访问此对象 - NOT AN UI OBJECT

问题描述

EDIT 我删除了我的代码,因为它不完整且令人困惑,但添加一个最小的可重现示例。为了澄清我的问题,下面的所有文字都经过了轻微的改写,从评论添加了信息,但没有添加任何我在提问时不知道的内容,以便使评论与未来的读者相关。我也改了标题

尝试在后台执行一些计算以使 UI 响应更快。

在尝试之前,我确保我的 Simulator 类工作正常。我的计算是通过从模拟器调用方法来启动的。当我尝试执行计算(无论是使用 await、TaskFactory 还是其他此类工具)时,我无法访问存储我需要的 3D 模型的 MeshGeometry3D 类成员:'调用线程无法访问此对象因为其他线程拥有它。'

我可以通过向任务传递参数来克服困难,但数据量非常大,因此如果可行,我更愿意处理现有对象。

我已阅读 thisthisthisthisthisthis这些答案都假定UI 元素,但事实并非如此:我的 MeshGeometry3D 成员未在 UI 中使用,在后台计算之前、期间或之后。

我读到这是人们开始使用时的常见问题,我应该在尝试访问属于主线程的数据时调用调度程序,但我无法从模拟器类访问调度程序(附带问题,有没有办法访问创建元素的调度程序?)

所以我试图了解正在发生的事情,以便决定处理问题的最佳方式。从我目前阅读的内容来看,我看到了 2 个选项:

  • 使用调度程序访问对象
  • 每次执行计算时都创建罪魁祸首 MeshGeometry3D

最小可重现示例

MainWindow.xaml.cs

using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Media3D;

namespace dispatcherObject
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Simulator Simulator;

        public MainWindow()
        {
            InitializeComponent();
            Simulator = new Simulator();
        }                  

        private void CreateMesh_Click(object sender,RoutedEventArgs e)
        {
            Simulator.mesh = new MeshGeometry3D();
        }

        private void AccessMesh_Click(object sender,RoutedEventArgs e)
        {
            CallSimulatorMethod();
        }  

        private async void CallSimulatorMethod()
        {
            await Task.Run(() =>Simulator.AccessMesh());
        }
    }
}

Simulator.cs

using System.Windows.Media.Media3D;

namespace dispatcherObject
{
    class Simulator
    {
        public MeshGeometry3D mesh;

        public void AccessMesh()
        {
            var foo = mesh.normals;
        }
    }
}

使用前面的代码,如果您先单击 AccessMesh 按钮,当然会得到 System.NullReferenceException。

如果你先点击 CreateMesh,你会得到这个异常:

system.invalidOperationException HResult=0x80131509 Message=调用线程无法访问该对象,因为其他线程拥有它。源=WindowsBase StackTrace:在 System.Windows.Threading.dispatcher.VerifyAccess() 在 System.Windows.DependencyObject.GetValue(DependencyProperty dp) 在 System.Windows.Media.Media3D.MeshGeometry3D.get_normals() 在 dispatcherObject.Simulator.AccessMesh() 中 C:\Users\geraud\source\repos\dispatcherObject\dispatcherObject\Simulator.cs:line 11 在 dispatcherObject.MainWindow.b__4_0() 中 C:\Users\geraud\source\repos\dispatcherObject\dispatcherObject\MainWindow.xaml.cs:line 33 在 System.Threading.Tasks.Task.InnerInvoke() 在 System.Threading.Tasks.Task.Execute()

这个异常最初是在这调用栈上抛出的: 【外码】 Simulator.cs 中的 dispatcherObject.Simulator.AccessMesh() dispatcherObject.MainWindow.CallSimulatorMethod.AnonymousMethod__4_0() 在 MainWindow.xaml.cs 中 [外部代码]

解决方法

感谢所有帮助我找到答案的评论员,尤其是@Knoop。

我试图访问从 DispatcherObject 继承的 MeshGeometry3D,来自创建它的不同线程。我通过在工作线程中重新创建对象来摆脱异常:

只有创建 Dispatcher 的线程才能访问 直接 DispatcherObject。

我想强调一个事实,这不是一个 UI 问题:虽然异常没有指定任何关于 UI 的内容,但它似乎主要遇到 UI 对象,如对我和 Stack Overflow 中的所有其他相关问题都清楚地显示出来。