C# – Form Controls Won’t Update with Multithreading

c++multithreadinguser-interfacewinforms

I've been playing around with multithreading and reading up on some of the questions here, but I haven't found an answer that directly addresses my concerns here.

I have an application that runs on a single thread, except for a progress bar in a separate window. Based on my research, I need to create a new thread for that form which will redraw the form's controls as it's properties change. I've reduced the problem to a simple example below:

Here's the 'main' program:

class Program
{
    static MyForm form;

    static void Main(string[] args)
    {
        form = new MyForm();
        form.Show();

        doWork();

        form.Close();
    }

    //arbitrary example of processing that takes some period of time
    static void doWork()
    {
        while (form.Value < 100000) 
        {
            form.ChangeVal();
            Thread.Sleep(1);
        }
        return;
    }
}

…And here's the Form. I'm not including the auto-generated stuff from VS.

public partial class MyForm : Form
{
    private int val;
    public int Value
    {
        get { return val; }
        set { val = value; }
    }

    public Thread GUIupdater;


    public MyForm()
    {
        InitializeComponent();
        this.Refresh();
    }

    private void MyForm_Load(object sender, EventArgs e)
    {
        GUIupdater = new Thread(new ThreadStart(GUIupdaterThread));
        GUIupdater.Start();

        this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(killThreadOnClose);
    }

    public void ChangeVal()
    {
        val++;
    }

    private void changeLabel(string s)
    {
        label.Text = s;
        label.Refresh();
    }
    private delegate void labelChanger(string s);
    private void GUIupdaterThread()
    {
        while (true)
        {
            Invoke(new labelChanger(changeLabel), new object[]{val.ToString()} );
            Thread.Sleep(100); //100 ms
        }
    }
    private void killThreadOnClose(object sender, FormClosingEventArgs e)
    {
        GUIupdater.Abort();
    }
}

So, my intention here is to have the calculations running constantly, with the window's graphics updating reasonably quickly. When I run the program, however, the invoke function is only called once, and the label never actually updates!

Any and all feedback is appreciated. If you want to view the code in an IDE you can download my project from Here

Edits:

  • When I add Console.WriteLine Statements, I discovered that the GUIupdaterThread (the thing that's meant to update the GUI) loop always 'breaks' on the Invoke statement, never reaching 'Thread.Sleep'. I changed it to 'BeginInvoke', which causes the loop to function properly, but this hasn't changed the fact that the GUI doesn't update.

CLARIFICATIONS:

About my 'actual' project:

  • The main thread here in 'Program' simulates my software, which is a plugin implementing an interface. My decision to alter val / value in that thread, not in the thread created by the window, was deliberate.
  • I'm constrained to using .NET 4.0 . any more recent features can't help me

Best Answer

Since in your application you have GUI thread (main thread) - all UI controls will be accessible from this thread only.

There are several approaches how to update controls from other threads. I would like to recommend you to use one of modern and native approaches based on Progress < T > class (it's native for .Net platform).

Related Question