The calling thread cannot access this object - NOT AN UI OBJECT

-2

EDIT I removed my code as it was incomplete and confusing, but added a minimal reproducible exemple. All the text below has been slightly rewritten to clarify my question, adding information from the comment, but without adding anything I didn't know when asking the question, in order to keep the comments relevant for a future reader. I also changed the title.

I'm trying to perform some calculations in the background to make UI more responsive.

Before trying that, I made sure my Simulator class works fine. My calculations are launched by calling a class method from Simulator. When I try to perform calculations (whether with await, TaskFactory or other such tools), I can't access the MeshGeometry3D class member that stores the 3D model I need : 'The calling thread cannot access this object because a different thread owns it.'

I could overcome the difficulty by passing arguments to the task, but the volume of data is quite big, so if that's feasable I would prefer working on a existing object.

I have read this, this, this, this, this and this but those answers all assume an UI element, and that's not the case : my MeshGeometry3D member is not used in the UI, before, during or after the background calculation.

I read that this is a common problem with people getting started, and that I should invoke the dispatcher when trying to access data that belong to the main thread, but I don't have access to the dispatcher from my simulator class (side question, is there a way to access the dispatcher that created an element ?)

So I'm trying to understand what is happening, in order to decide the best way to handle the problem. From what I read so far, I see 2 options :

  • Use a dispatcher to access the object
  • Create the culprit MeshGeometry3D each time I perform the calculations

Minimal reproducible example

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;
        }
    }
}

With the previous code, if you click the AccessMesh button first, you get a System.NullReferenceException, of course.

If you click CreateMesh first, you get this exception :

System.InvalidOperationException HResult=0x80131509 Message=The calling thread cannot access this object because a different thread owns it. Source=WindowsBase StackTrace: at System.Windows.Threading.Dispatcher.VerifyAccess() at System.Windows.DependencyObject.GetValue(DependencyProperty dp) at System.Windows.Media.Media3D.MeshGeometry3D.get_Normals() at DispatcherObject.Simulator.AccessMesh() in C:\Users\geraud\source\repos\DispatcherObject\DispatcherObject\Simulator.cs:line 11 at DispatcherObject.MainWindow.b__4_0() in C:\Users\geraud\source\repos\DispatcherObject\DispatcherObject\MainWindow.xaml.cs:line 33 at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute()

This exception was originally thrown at this call stack: [External Code] DispatcherObject.Simulator.AccessMesh() in Simulator.cs DispatcherObject.MainWindow.CallSimulatorMethod.AnonymousMethod__4_0() in MainWindow.xaml.cs [External Code]

c#
multithreading
dispatcher
multitasking
asked on Stack Overflow Feb 8, 2021 by geriwald • edited Feb 9, 2021 by geriwald

1 Answer

1

Thanks to all the commentators that helped me found the answer, and especially @Knoop.

I was trying to access a MeshGeometry3D, that inherits from DispatcherObject, from a different thread that the one it was created on. I got rid of the exception by recreating the object in the worker thread :

Only the thread that the Dispatcher was created on may access the DispatcherObject directly.

I would like to stress the fact that it was not a UI problem : Though the exception doesn't specify anything about UI, it seems to be mainly encountered with UI objects, as the comments on my and all other related questions in Stack Overflow clearly show.

answered on Stack Overflow Feb 8, 2021 by geriwald • edited Feb 9, 2021 by geriwald

User contributions licensed under CC BY-SA 3.0