Page 1 of 1

NoesisException: Calling thread (7516) doesn't have access to this object (5556)

Posted: 03 Dec 2017, 13:35
by mmgftw
I've come across an annoying error. Apparently I'm calling some code from another thread.

Setup
I've got a GameManager (Monobehaviour) class which holds a bunch of commands (can be added from anywhere in the code) which need to be executed on various objects. One of those commands is the switching of a view. When the Update() method is called on the GameManager, all the commands which were stored are getting called on the listeners.
One of those listeners is my viewmodel for my main view. It listens for a change of view command and executes the code to load a xaml from code.

Classes
MainViewModel
public class MainVM : BaseVM, IChangeUIViewCommand
    {
        #region Private Fields

        private Panel _contentContainer;

        #endregion Private Fields

        #region Public Constructors

        public MainVM(Panel contentContainer) : base()
        {
            _contentContainer = contentContainer;
            GameManager.Subscribe(this, Enums.CommandType.ChangeUIView);
        }

        #endregion Public Constructors
        
        #region Public Methods

        public void ChangeUI(Enums.UILevel uiLevel)
        {
            object usercontrol = null;
            _contentContainer.Children.Clear();

            var xamlLocation = "";
            switch (uiLevel)
            {
                case Enums.UILevel.None:
                    break;

                case Enums.UILevel.Login:
                    xamlLocation = "Assets/UI/Views/Login.xaml";
                    break;

                case Enums.UILevel.CharacterSelection:
                    xamlLocation = "Assets/UI/Views/CharacterSelection.xaml";
                    break;

                case Enums.UILevel.CharacterCreation:
                    xamlLocation = "Assets/UI/Views/CharacterCreation.xaml";
                    break;

                case Enums.UILevel.Ingame:
                    xamlLocation = "Assets/UI/Views/Ingame.xaml";
                    break;

                case Enums.UILevel.Loading:
                    xamlLocation = "Assets/UI/Views/Loading.xaml";
                    break;
            }
            usercontrol = Noesis.GUI.LoadXaml(xamlLocation);

            if (usercontrol != null)
                _contentContainer.Children.Add(usercontrol);
        }

        #endregion Public Methods
    }
GameManager (relevant part)
 private void Update()
    {
        while (_commandQueue.Count > 0)
        {
            var command = _commandQueue.Dequeue();
            if (command.IsNetworkCommand)
                ExecuteNetworkCommand(command);
            else
                ExecuteLocalCommand(command);

            command.Recycle();
        }
    }
    
    private void ExecuteLocalCommand(Command command)
    {
        var commandListenersByType = _commandListeners[command.CommandType];
        for (int j = 0; j < commandListenersByType.Count; j++)
            command.Execute(commandListenersByType[j]);
    }
Stacktrace
PulatiaUI.CharacterSelection:.ctor() (at Assets/UI/Views/CharacterSelection.xaml.cs:36)
System.Runtime.CompilerServices.ExecutionScope:lambda_method(ExecutionScope)
Noesis.Extend:CreateInstance(IntPtr, IntPtr) (at Assets/NoesisGUI/Plugins/API/Core/NoesisExtend.cs:3887)
Noesis.GUI:Noesis_LoadXaml(String)
Noesis.GUI:Noesis_LoadXaml_(String) (at Assets/NoesisGUI/Plugins/API/Core/NoesisGUI.cs:262)
Noesis.GUI:LoadXaml(String) (at Assets/NoesisGUI/Plugins/API/Core/NoesisGUI.cs:120)
Assets.UI.ViewModels.MainVM:ChangeUI(UILevel) (at Assets/UI/ViewModels/MainVM.cs:90)
Pulatia.Network.Common.Commands.ChangeUIViewCommand:Execute(ICommandListener)
GameManager:ExecuteLocalCommand(Command) (at Assets/Scripts/Managers/GameManager.cs:141)
GameManager:Update() (at Assets/Scripts/Managers/GameManager.cs:116)

Re: NoesisException: Calling thread (7516) doesn't have access to this object (5556)

Posted: 04 Dec 2017, 10:29
by sfernandez
Hi,

In NoesisGUI UI elements can only be accessed from the thread where they were created, and they should live in the same thread as the View where they are connected to.
Could you please create a ticket in our bugtracker and attach your project files. This way we can help you figure out which elements are being accessed from the incorrect thread.

Thanks.

Re: NoesisException: Calling thread (7516) doesn't have access to this object (5556)

Posted: 04 Dec 2017, 20:23
by mmgftw
Thank you for getting back at me. Here is some more information, because it might just be some misunderstanding from my part about the threads being used here.
Image

In the above image, the [Managers] gameobject is using the same thread as the "Noesis View" with the Main.xaml file right? The MainVM class I mentioned in my original post is assigned to the datacontext for the Main.xaml. Am I correcty in saying that the MainVM class is running on the same thread as the [Managers] gameobject?

When using the Noesis.GUI.LoadXaml(xamlLocation) method, the loaded xaml is also on the same thread as the Main.xaml (meaning on the same thread as the Managers gameobject aswell) right? Or am I wrong here?
PS: All my loaded xamls are being added to the Main.xaml as children of a grid in that Main.xaml.

Re: NoesisException: Calling thread (7516) doesn't have access to this object (5556)

Posted: 11 Dec 2017, 12:18
by jsantos
As you are not the first user reporting this problem, we think there may be a bug in Noesis regarding this. You are not using threads in your application right? Would it be possible to have a copy of your project to analyze and reproduce the issue? (in the tracker)

Thanks!

Re: NoesisException: Calling thread (7516) doesn't have access to this object (5556)

Posted: 12 Dec 2017, 11:31
by sfernandez
Do you have any script that creates any Noesis UI element or resource as a static field?

Something like this:
public class TestBehavior: MonoBehavior
{
  private static Noesis.TextBlock textBlock = new TextBlock();
  ...
}
Because that will lead to Unity initializing that field during UnityPreload thread, which executes Noesis initialization in the incorrect thread.

Re: NoesisException: Calling thread (7516) doesn't have access to this object (5556)

Posted: 12 Dec 2017, 11:57
by sfernandez
I found the following in Unity forums:
Monobehaviours can't have Constructors.
The reason for this is that in Editor, to fill up the Inspector they get created/destroyed on a separate editor thread. This causes Unity threading issues primarily, but will also cause more strange issues because you can't reference singletons or some static variables, as the object is being created completely out of the game flow.