Accessing Controls running in different Thread

Posted on 4 830 views

If you worked with System.Threading.Thread in desktop applications, you probably ran into problem, where you wanned to access some control, and update her condition / property.

Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread.

At compile time, everything works fine, but when you start some void with ThreadStart it throwed you InvalidOperationException with message: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.

THE SOLUTION of this problem is:

using System;
using System.Windows.Forms;

using System.Reflection;
using System.Threading;

namespace MB.AccessingControlsRunningInDifferentThread
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(new ThreadStart(DoSomething));
            thread.Start();
        }

        public void DoSomething()
        {
            // This DOESN'T work at runtime, because it throws 'InvalidOperationException'
            // textBox1.Text = "Text entered from another thread!";

            // PROBLEM FIX 
            SetControlPropertyValue(textBox1, "Text", "Text entered from another thread!");
        }

        delegate void SetControlValueCallback(Control control, string propertyName, object propertyValue);

        private void SetControlPropertyValue(Control control, string propertyName, object propertyValue)
        {
            // ----------------
            // InvokeRequired
            // ----------------
            // Gets a value indicating whether the caller must call an invoke method 
            // when making method calls to the control because the caller is in 
            // different thread than the one the control was created on.
            if (control.InvokeRequired)
            {
                SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
                control.Invoke(d, new object[] { control, propertyName, propertyValue });
            }
            else
            {
                Type t = control.GetType();

                // From System.Reflection
                PropertyInfo[] properties = t.GetProperties();

                foreach (PropertyInfo property in properties)
                {
                    if (property.Name.ToUpper() == propertyName.ToUpper())
                    {
                        property.SetValue(control, propertyValue, null);
                    }
                }
            }
        }
    }
}