问题描述
EDIT 我删除了我的代码,因为它不完整且令人困惑,但添加了一个最小的可重现示例。为了澄清我的问题,下面的所有文字都经过了轻微的改写,从评论中添加了信息,但没有添加任何我在提问时不知道的内容,以便使评论与未来的读者相关。我也改了标题。
我尝试在后台执行一些计算以使 UI 响应更快。
在尝试之前,我确保我的 Simulator
类工作正常。我的计算是通过从模拟器调用类方法来启动的。当我尝试执行计算(无论是使用 await、TaskFactory 还是其他此类工具)时,我无法访问存储我需要的 3D 模型的 MeshGeometry3D
类成员:'调用线程无法访问此对象因为其他线程拥有它。'
我可以通过向任务传递参数来克服困难,但数据量非常大,因此如果可行,我更愿意处理现有对象。
我已阅读 this、this、this、this、this 和 this 但这些答案都假定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 中的所有其他相关问题都清楚地显示出来。