Page 1 of 1

Cross Threading Template : How To Access Controls On Other Threads

#1 Sheepings   User is offline

  • Senior Programmer
  • member icon

Reputation: 95
  • View blog
  • Posts: 701
  • Joined: 05-December 13

Posted 30 August 2018 - 01:25 PM

I wrote this as an example piece for cross-threading operations which allows you to send values to and from non gui threads. It is very well commented and explained, so I will keep the introduction to this piece simple.

Controls and [email protected]

TB1 As TextBox

TB2 As TextBox

listBox1 As ListBox

Button4 As Button

Variable [email protected]
// Updates the textbox1 text.
        private void UpdateTextB1(string text) //This is the method the callback will work with for TB1.
        {
            // Set the textbox1 text.
            TB1.Text = text;
        }

        // Updates the textbox2 text.
        private void UpdateTextB2(string text) //This is the method the callback will work with for TB2.
        {
            // Set the textbox text.
            TB2.Text = text;
        }

        // Updates the listbox item.
        private void UpdateLB(string text, string text2) //This is the method the callback will work with for ListBox1.
        {
            // Set the listbox item.
            listBox1.Items.Add(text + " " + text2);
        }


Declared delegate [email protected]
       
        public delegate void UpdateTextB1Callback(string text); //For TextBox1 named TB1.

        public delegate void UpdateTextB2Callback(string text); //For TextBox2 named TB2.

        public delegate void UpdateLBCallback(string string1, string string2); //For ListBox1 named ListBox1.



Button4 [email protected]
private void button4_Click(object sender, EventArgs e)
        {
            //At this section we will declare a new thread and provide it with its two parameters. i1 and i2,
            //because that is what is required by the NonUIThread void. (You'll see this further down.)
            var UodateThread = new Thread(() => NonUIThread(i1, i2)); //Pass the variables to the method.

            bgw.RunWorkerAsync(); UodateThread.Start(); //We are simply running both the background worker and
            //the non UI thread.
        }



Background Worker Do Work [email protected]

private void bgw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            //So we want to access TB1 but its on another thread, (the thread it was probably created on)
            //To do this, we will need a delegate called UpdateTextB1Callback, and it requires a method.
            //The method we will be using is UpdateTextB1, and it takes one parameter.
            TB1.Invoke(new UpdateTextB1Callback(UpdateTextB1),
                        new string[] { "Text sent on non-UI BG Worker with no variables." });

            //Since we know that the control is on another thread and we can't access it, we don't need to
            //check with an if statement if the control needs invoking, so we will just invoke it, since we
            //know it needs invoking, and checking is not required anyway. I've provided the commented code below
            //for reference purposes... to check if a control needs updating, just use TB1 as control example
            //and do:

            //if (TB1.InvokeRequired)
            //{
            //    TB1.Invoke(:action:);
            //    //If you uncomment this statement, you will find an error in the code where action is.
            //    //This is where you must insinuate your own action for that invoke method. Below are two examples.
            //}
            //else { } //The control doesn't need invoking, do as you please.
        }



Non UI Thread and summery [email protected]
private void NonUIThread(string a, string B ) 
        {
            TB2.Invoke(new UpdateTextB2Callback(UpdateTextB2),
                          new object[] { "Text sent on non-UI thread with variables. "
                          + a + " from string i1. And a value of " + b + " from string i2" });

            //I would like to point out two things, between these two. The one above is a non-safe method
            //because it used an object which is a base type. In codeology, anything can be an object, so it
            //can be manipulated. The one below is not exactly the best way to do this either, but its one of
            //the most practiced and preferred among some developers, as it does exactly as intended, and its
            //the easiest way to pass information between different threads.
            listBox1.Invoke(new UpdateLBCallback(UpdateLB),
                          new string[] { "New", "List Item" });

            //Conclusion... You might be wondering how the last bit on line 91, 92 works. But just look at the
            //code and you can see how it works, and what the delegate is doing with the method to pass the values.
            //I didn't write this as a tutorial. But I just felt like some of it needed commenting for clarity. :)/>/>/>/>/>

            //Further to draw a close and some things to try. If you know what your threads are doing and how they
            //are accessing your data, then you can use (this NON recommended bool) to skip cross threading issues.

            //CheckForIllegalCrossThreadCalls = false; will allow your application to interact without the need
            //for the above methods and multi-threading or cross-threading methods. Again, this is not something
            //I advocate using, as it can cause monstrous problems on big applications responsible for handing data etc.

            //Put at the top of the void "CheckForIllegalCrossThreadCalls = false;" in place of this (Without COMMENTS //):
            //TB2.Invoke(new UpdateTextB2Callback(UpdateTextB2),
            //              new object[] { "Text sent on non-UI thread with variables. "
            //              + a + " from string i1. And a value of " + b + " from string i2" });
            //And above it, put //CheckForIllegalCrossThreadCalls = false; at the top of the void (inside).
            //Now execute and you will find you are able to access your controls without restrictions, and this
            //is because of the bool we used at the top of the method. I hope this helps some people out there,
            //as you could use this as a template to cross-threading and passing values to different threads.
        }



Tested and working perfectly on .Net Framework 4.5.2.
Class as it stands is an example piece which can be used as a template for cross threading [email protected]

        //Lets define our delegates below
        public delegate void UpdateTextB1Callback(string text); //For TextBox1 named TB1.

        public delegate void UpdateTextB2Callback(string text); //For TextBox2 named TB2.

        public delegate void UpdateLBCallback(string string1, string string2); //For ListBox1 named ListBox1.

        //Declare two variables, we can use these to pass them between threads.
        private string i1 = "String A"; private string i2 = "String B";

        // Updates the textbox1 text.
        private void UpdateTextB1(string text) //This is the method the callback will work with for TB1.
        {
            // Set the textbox1 text.
            TB1.Text = text;
        }

        // Updates the textbox2 text.
        private void UpdateTextB2(string text) //This is the method the callback will work with for TB2.
        {
            // Set the textbox text.
            TB2.Text = text;
        }

        // Updates the listbox item.
        private void UpdateLB(string text, string text2) //This is the method the callback will work with for ListBox1.
        {
            // Set the listbox item.
            listBox1.Items.Add(text + " " + text2);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            //At this section we will declare a new thread and provide it with its two parameters. i1 and i2,
            //because that is what is required by the NonUIThread void. (You'll see this further down.)
            var UodateThread = new Thread(() => NonUIThread(i1, i2)); //Pass the variables to the method.

            bgw.RunWorkerAsync(); UodateThread.Start(); //We are simply running both the background worker and
            //the non UI thread.
        }

        private void bgw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            //So we want to access TB1 but its on another thread, (the thread it was probably created on)
            //To do this, we will need a delegate called UpdateTextB1Callback, and it requires a method.
            //The method we will be using is UpdateTextB1, and it takes one parameter.
            TB1.Invoke(new UpdateTextB1Callback(UpdateTextB1),
                        new string[] { "Text sent on non-UI BG Worker with no variables." });

            //Since we know that the control is on another thread and we can't access it, we don't need to
            //check with an if statement if the control needs invoking, so we will just invoke it, since we
            //know it needs invoking, and checking is not required anyway. I've provided the commented code below
            //for reference purposes... to check if a control needs updating, just use TB1 as control example
            //and do:

            //if (TB1.InvokeRequired)
            //{
            //    TB1.Invoke(:action:);
            //    //If you uncomment this statement, you will find an error in the code where action is.
            //    //This is where you must insinuate your own action for that invoke method. Below are two examples.
            //}
            //else { } //The control doesn't need invoking, do as you please.
        }

        private void NonUIThread(string a, string B ) 
        {
            TB2.Invoke(new UpdateTextB2Callback(UpdateTextB2),
                          new object[] { "Text sent on non-UI thread with variables. "
                          + a + " from string i1. And a value of " + b + " from string i2" });

            //I would like to point out two things, between these two. The one above is a non-safe method
            //because it used an object which is a base type. In codeology, anything can be an object, so it 
            //can be manipulated. The one below is not exactly the best way to do this either, but its one of 
            //the most practiced and preferred among some developers, as it does exactly as intended, and its 
            //the easiest way to pass information between different threads.
            listBox1.Invoke(new UpdateLBCallback(UpdateLB),
                          new string[] { "New ", "List Item" });

            //Conclusion... You might be wondering how the last bit on line 91, 92 works. But just look at the
            //code and you can see how it works, and what the delegate is doing with the method to pass the values.
            //I didn't write this as a tutorial. But I just felt like some of it needed commenting for clarity. :)/>/>/>/>/>

            //Further to draw a close and some things to try. If you know what your threads are doing and how they
            //are accessing your data, then you can use (this NON recommended bool) to skip cross threading issues.

            //CheckForIllegalCrossThreadCalls = false; will allow your application to interact without the need
            //for the above methods and multi-threading or cross-threading methods. Again, this is not something
            //I advocate using, as it can cause monstrous problems on big applications responsible for handing data etc.

            //Put at the top of the void "CheckForIllegalCrossThreadCalls = false;" in place of this (Without COMMENTS //):
            //TB2.Invoke(new UpdateTextB2Callback(UpdateTextB2),
            //              new object[] { "Text sent on non-UI thread with variables. "
            //              + a + " from string i1. And a value of " + b + " from string i2" });
            //And above it, put //CheckForIllegalCrossThreadCalls = false; at the top of the void (inside).
            //Now execute and you will find you are able to access your controls without restrictions, and this
            //is because of the bool we used at the top of the method. I hope this helps some people out there,
            //as you could use this as a template to cross-threading and passing values to different threads. 
        }

        #endregion Multithreading
    }
}



[email protected]

Edited: Fixed a typo from submission

Attached image(s)

  • Attached Image

This post has been edited by Sheepings: 31 August 2018 - 09:46 AM


Is This A Good Question/Topic? 0
  • +

Page 1 of 1