nizesh
Topic Author
Posts: 11
Joined: 31 Jul 2019, 22:32

The calling thread cannot access this object because a different thread owns it.

07 Aug 2019, 18:03

I'm trying to render a CustomCanvas view programmatically
 public class GraphCanvas : Canvas {
 	...
 	public void renderGraph()
        {
            Rectangle rect = new Rectangle();
            rect.Width = 200;
            rect.Height = 100;
            rect.Fill = Brushes.Blue;
            this.Children.Add(rect);
          }
 }
I'm calling this method
renderGraph();
from another class but it's giving me this error
The calling thread cannot access this object because a different thread owns it.
What's the fix for this?
 
User avatar
jsantos
Site Admin
Posts: 3905
Joined: 20 Jan 2012, 17:18
Contact:

Re: The calling thread cannot access this object because a different thread owns it.

08 Aug 2019, 12:30

Are you invoking that function from a different thread than the one used to create the object?
 
nizesh
Topic Author
Posts: 11
Joined: 31 Jul 2019, 22:32

Re: The calling thread cannot access this object because a different thread owns it.

08 Aug 2019, 16:47

Yeah. The place from where I'm calling that function is the place where I receive my data. The logic I'm trying to implement is whenever the data gets updated, the UI needs to be invalidated as well. I think that error message is showing up because I'm trying to access the UI thread from the main thread but I don't know how to get over it. Apparantly, the
Dispatcher.Invoke
method didn't seem to work. What ways can we invalidate the UI through a thread outside the UI thread?
 
User avatar
jsantos
Site Admin
Posts: 3905
Joined: 20 Jan 2012, 17:18
Contact:

Re: The calling thread cannot access this object because a different thread owns it.

08 Aug 2019, 17:14

Noesis objects created in one thread cannot be accessed from a different thread. We don't provide a mechanism to solve that, you need to do it yourself, depending on the platform you are using.

If Dispatcher is not available in Unity, what the recommended mechanism then?
 
wyvern010
Posts: 31
Joined: 18 Apr 2019, 13:41

Re: The calling thread cannot access this object because a different thread owns it.

17 Nov 2019, 16:18

I also ran in some of these issues when updating the ViewModel from outside the rendering thread.
Here is my fix, although i think there should be a better way.
Note that i'm not using Unity, but Dispatcher is not available in the Noesis App framework.
I use the below patern: Save to List -> OnRender() -> Execute everything in the list.
 public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        static object syncObject = new object();
        static List<Tuple<PropertyChangedEventHandler, string, object>> asynclist = new List<Tuple<PropertyChangedEventHandler, string, object>>();
            private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (_synchronizationContext == SynchronizationContext.Current)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
            else
            {
                lock (syncObject)
                    asynclist.Add(new Tuple<PropertyChangedEventHandler, string, object>(this.PropertyChanged, propertyName, this));
            }
        }

        public static void consumeAsyncList()
        {
            lock (syncObject)
            {
                foreach (var tuple in asynclist)
                {
                // PropertyChanged now gets invoked on the Noesis Gui thread.
                    tuple.Item1?.Invoke(tuple.Item3, new PropertyChangedEventArgs(tuple.Item2));
                }
                acynclist.clear();
            }
        }
}
Then in MainWindow:
 public partial class MainWindow : Window
 {
 	//...
 	public MainWindow() 
        {
            SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
            this.Rendering += MainWindow_Rendering;
            //.....
        }
        private void MainWindow_Rendering(object sender, WindowRenderingEventArgs e)
        { 
            ViewModels.ViewModelBase.consumeAsyncList();
        }
}
I Also tried the common _synchronizationContext.Send/Post way, but i got the same errors, or it didn't update at all.
 
User avatar
sfernandez
Site Admin
Posts: 2983
Joined: 22 Dec 2011, 19:20

Re: The calling thread cannot access this object because a different thread owns it.

18 Nov 2019, 16:56

For next 2.2.6 release we implemented DispatcherObject.Dispatcher property and CheckAccess() method for C# SDK: #1470, #1548
So you will be able to simplify your code to something like this:
public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (_dispatcher.CheckAccess())
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        else
        {
            _dispatcher.BeginInvoke(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)););
        }
    }
}
 
User avatar
stonstad
Posts: 241
Joined: 06 Jun 2016, 18:14
Location: Lesser Magellanic Cloud
Contact:

Re: The calling thread cannot access this object because a different thread owns it.

12 Dec 2019, 19:13

A late reply... but the UnityDispatcher class here (viewtopic.php?f=3&t=1659&p=9570&hilit=dispatcher#p9570) might be helpful for placing UI work back on the main thread.
 
User avatar
jsantos
Site Admin
Posts: 3905
Joined: 20 Jan 2012, 17:18
Contact:

Re: The calling thread cannot access this object because a different thread owns it.

16 Dec 2019, 19:09

Thanks for sharing this! For those of you that can't wait, the imminent 2.2.6 will have the standard Dispatcher class implemented.
 
User avatar
stonstad
Posts: 241
Joined: 06 Jun 2016, 18:14
Location: Lesser Magellanic Cloud
Contact:

Re: The calling thread cannot access this object because a different thread owns it.

18 Dec 2019, 15:54

This new dispatcher class --- does it queue up work for the main thread, and then execute on the next frame rendered? Also interested to know if it runs logic without queuing if execution is already on the main thread?
 
User avatar
sfernandez
Site Admin
Posts: 2983
Joined: 22 Dec 2011, 19:20

Re: The calling thread cannot access this object because a different thread owns it.

18 Dec 2019, 17:34

Dispatcher API allows you to call:
- CheckAccess() to determine if calling thread is the same as the one associated with the Dispatcher.
- BeginInvoke() to execute the specified action asynchronously on the thread the Dispatcher is associated with.
- Invoke() to execute synchronously on the thread the Dispatcher is associated with (this is a blocking call).

So BeginInvoke will enqueue a task and execute later (next frame probably) on Dispatcher's thread.
And Invoke will enqueue the task and block only when not executing on Dispatcher's thread, otherwise it just executes the task.

Who is online

Users browsing this forum: Ahrefs [Bot] and 82 guests