How do I resolve, get_isActiveAndEnabled can only be called from the main thread error

below is my script that i have attached to an empty game object. I made sure to assign the dropdown and text fields to the respective object accordingly(In the properties inspector).

below is a copy of my class.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

//Access the DarkRift namespace
using DarkRift;
using System;
using System.Net.Sockets;
using System.Timers;

public class Manager : MonoBehaviour {

    public Dropdown dropdown;

    public Text myText;

    public Timer timer;

    public string serverSelection = "";

    public string serverIP = "";

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
    public void connectButtonClickHandler()
    {
        print("Connecting to " + serverIP.ToString());

        //attempt to connect to the server.
        //Connect to the DarkRift Server using the Ip specified (will hang until connected or timeout)
        try
        {
            DarkRiftAPI.Connect (serverIP);
        } catch(Exception ex)
        {
            print("Cannot connect to. " + serverIP.ToString());
            print("Message: " + ex.Message);
        }

        //Setup a receiver so we can create players when told to.
        DarkRiftAPI.onDataDetailed += ReceiveData;

        //Tell others that we've entered the game and to instantiate a player object for us.
        if (DarkRiftAPI.isConnected)
        {
            print("Connected to server");
            //Get everyone else to tell us to spawn them a player (this doesn't need the data field so just put whatever)
            //DarkRiftAPI.SendMessageToOthers (TagIndex.Controller, TagIndex.ControllerSubjects.JoinMessage, "hi");
            //Then tell them to spawn us a player! (this time the data is the spawn position)
            //DarkRiftAPI.SendMessageToAll (TagIndex.Controller, TagIndex.ControllerSubjects.SpawnPlayer, new Vector3(0f,0f,0f));
        }
        else
            print("Failed to connect to DarkRift Server!");

            //display a message
            myText.text = "Failed to connect to server: " + serverIP.ToString();

            //set a timer that makes the message dissapear eventually
            timer = new Timer();
            timer.Interval = 3000;
            timer.AutoReset = false;
            timer.Elapsed += onTimerTick;
            //start the timer
            timer.Start();

            //go back to Connect screen

    }
    public void onTimerTick(System.Object source, ElapsedEventArgs e)
    {
        print("tick!");
        //empty the error text
        myText.text = "";
    }
    public void onServerSelectionChange()
    {
        print("Changed..!");

        if(dropdown.value == 0)
        {
            //Canada selected
            serverSelection = "Canada";
            serverIP = "127.0.0.1";
            print("Canada selected!");
        } else if(dropdown.value == 1)
        {
            //United States selected
            serverSelection = "United States";
            serverIP = "google.com";
            print("United States selected!");
        }
    }
    void ReceiveData (ushort senderID, byte tag, ushort subject, object data)
    {
        print("data received!");
        //When any data is received it will be passed here, 
        //we then need to process it if it's got a tag of 0 and, if 
        //so, create an object. This is where you'd handle most admin 
        //stuff like that.

        //Ok, if data has a Controller tag then it's for us
//        if (tag == TagIndex.Controller)
//        {
//            //If a player has joined tell them to give us a player
////            if (subject == TagIndex.ControllerSubjects.JoinMessage) 
////            {
////                //Basically reply to them.
//////                DarkRiftAPI.SendMessageToID (senderID, TagIndex.Controller, TagIndex.ControllerSubjects.SpawnPlayer, player.position);
////            }
//
//            //Then if it has a spawn subject we need to spawn a player
////            if (subject == TagIndex.ControllerSubjects.SpawnPlayer)
////            {
////                //Instantiate the player
////                //GameObject clone = (GameObject)Instantiate (playerObject, (Vector3)data, Quaternion.identity);
////                //Tell the network player who owns it so it tunes into the right updates.
////                //clone.GetComponent<NetworkPlayer>().networkID = senderID;
////
////                //If it's our player being created allow control and set the reference
//////                if (senderID == DarkRiftAPI.id)
//////                {
//////                    //clone.GetComponent<Player>().isControllable = true;
//////                   // player = clone.transform;
//////                }
////            }
//        }
    }
}

The problem happens in my timer elapsed event handler, on the below line when i try to set the Text’s text property. I also have a click button handler in there as you can see.

myText.text = “”;

Very simply from what I can tell you are using another thread to connect to the server. Since unity isn’t technically thread compatible, anything other than the usual C# you can’t do in a thread. What I would recommend doing is creating a String. Set the string = to what you were setting myText.text to. Then in Update() set myText.text = equal to the string either each frame or have a boolean set up so that it will only update when it changes. Here’s the code :

 using UnityEngine;
 using UnityEngine.UI;
 using System.Collections;
 
 //Access the DarkRift namespace
 using DarkRift;
 using System;
 using System.Net.Sockets;
 using System.Timers;
 
 public class Manager : MonoBehaviour {
 
     public Dropdown dropdown;
 
     public Text myText;
 
     public Timer timer;
 
     public string serverSelection = "";
 
     public string serverIP = "";
 
     string text;

     // Use this for initialization
     void Start () {
     
     }
     
     // Update is called once per frame
     void Update () {
             myText.text = text;
     }
     public void connectButtonClickHandler()
     {
         print("Connecting to " + serverIP.ToString());
 
         //attempt to connect to the server.
         //Connect to the DarkRift Server using the Ip specified (will hang until connected or timeout)
         try
         {
             DarkRiftAPI.Connect (serverIP);
         } catch(Exception ex)
         {
             print("Cannot connect to. " + serverIP.ToString());
             print("Message: " + ex.Message);
         }
 
         //Setup a receiver so we can create players when told to.
         DarkRiftAPI.onDataDetailed += ReceiveData;
 
         //Tell others that we've entered the game and to instantiate a player object for us.
         if (DarkRiftAPI.isConnected)
         {
             print("Connected to server");
             //Get everyone else to tell us to spawn them a player (this doesn't need the data field so just put whatever)
             //DarkRiftAPI.SendMessageToOthers (TagIndex.Controller, TagIndex.ControllerSubjects.JoinMessage, "hi");
             //Then tell them to spawn us a player! (this time the data is the spawn position)
             //DarkRiftAPI.SendMessageToAll (TagIndex.Controller, TagIndex.ControllerSubjects.SpawnPlayer, new Vector3(0f,0f,0f));
         }
         else
             print("Failed to connect to DarkRift Server!");
 
             //display a message
             myText.text = "Failed to connect to server: " + serverIP.ToString();
 
             //set a timer that makes the message dissapear eventually
             timer = new Timer();
             timer.Interval = 3000;
             timer.AutoReset = false;
             timer.Elapsed += onTimerTick;
             //start the timer
             timer.Start();
 
             //go back to Connect screen
 
     }
     public void onTimerTick(System.Object source, ElapsedEventArgs e)
     {
         print("tick!");
         //empty the error text
         text ="";
     }
     public void onServerSelectionChange()
     {
         print("Changed..!");
 
         if(dropdown.value == 0)
         {
             //Canada selected
             serverSelection = "Canada";
             serverIP = "127.0.0.1";
             print("Canada selected!");
         } else if(dropdown.value == 1)
         {
             //United States selected
             serverSelection = "United States";
             serverIP = "google.com";
             print("United States selected!");
         }
     }
     void ReceiveData (ushort senderID, byte tag, ushort subject, object data)
     {
         print("data received!");
         //When any data is received it will be passed here, 
         //we then need to process it if it's got a tag of 0 and, if 
         //so, create an object. This is where you'd handle most admin 
         //stuff like that.
 
         //Ok, if data has a Controller tag then it's for us
 //        if (tag == TagIndex.Controller)
 //        {
 //            //If a player has joined tell them to give us a player
 ////            if (subject == TagIndex.ControllerSubjects.JoinMessage) 
 ////            {
 ////                //Basically reply to them.
 //////                DarkRiftAPI.SendMessageToID (senderID, TagIndex.Controller, TagIndex.ControllerSubjects.SpawnPlayer, player.position);
 ////            }
 //
 //            //Then if it has a spawn subject we need to spawn a player
 ////            if (subject == TagIndex.ControllerSubjects.SpawnPlayer)
 ////            {
 ////                //Instantiate the player
 ////                //GameObject clone = (GameObject)Instantiate (playerObject, (Vector3)data, Quaternion.identity);
 ////                //Tell the network player who owns it so it tunes into the right updates.
 ////                //clone.GetComponent<NetworkPlayer>().networkID = senderID;
 ////
 ////                //If it's our player being created allow control and set the reference
 //////                if (senderID == DarkRiftAPI.id)
 //////                {
 //////                    //clone.GetComponent<Player>().isControllable = true;
 //////                   // player = clone.transform;
 //////                }
 ////            }
 //        }
     }
 }