3

I want to learn more about threading and created a little test application that change the backcolor of a label.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    //lblColor
    public Color theLabel
    {
        get { return this.lblColor.BackColor;  }
        set { this.lblColor.BackColor = value; }
    }

    //btnStart
    private void btnStart_Click(object sender, EventArgs e)
    {
        ThreadTest cColor = new ThreadTest();
        Thread tColor = new Thread(new ThreadStart(cColor.ChangeColor));

        tColor.Start();
    }
}

And...

public class ThreadTest
{
    public void ChangeColor()
    {
        Form1 foo = new Form1();
        while (true)
        {
            foo.theLabel = Color.Aqua;
            foo.theLabel = Color.Black;
            foo.theLabel = Color.DarkKhaki;
            foo.theLabel = Color.Green;
        }
     }
}

The only problem is why can't i make this code work? I can see that the code in ChangeColor runs but the color of the label don't change.

Danode
  • 95
  • 2
  • 5
  • 2
    That's because your thread isn't asynchronous...the form does reside on the same thread as your changing code, and so the form has no chance to redraw itself. I'm just too lazy to form now an answer which explains exactly why and how to use delegates. – Bobby Nov 05 '10 at 14:53
  • As stated in my answer below, the code is not working because of Form1 foo = new Form1(); in ThreadTest.ChangeColor... use parameterized thread start... all suggestions regarding backgroundworker etc are also good ideas. – Chris Baxter Nov 05 '10 at 15:00

4 Answers4

5

At first glance, you are constructing a new form

Form1 foo = new Form1(); 

inside ThreadTest and never displaying the form, my guess is you intended to change the form color on the form with btnStart? You have two options, either pass in the form in to a ParameterizedThreadStart or re-write the code to just operate on the existing form.

Also, based on the code written, you will likely need to use Invoke to update the state of the form as you cannot have worker threads update the UI. I will tweak your code and posted a revised example if someone doesn't beat me to it.

Edit

In this case you don't need the invoke... but here is what I think you were intending...

private void btnStart_Click(object sender, EventArgs e)
{
  ThreadTest cColor = new ThreadTest();
  Thread tColor = new Thread(new ParameterizedThreadStart(cColor.ChangeColor));

  tColor.Start(this);
}

public class ThreadTest
{
  public void ChangeColor(Object state)
  {
    Form1 foo = (Form1) state;
    while (true)
    {
      foo.theLabel = Color.Aqua;
      foo.theLabel = Color.Black;
      foo.theLabel = Color.DarkKhaki;
      foo.theLabel = Color.Green;
    }
  }
} 

Also, it is important to set worker threads as background threads, otherwise when you close the form, the thread will keep that appliaction open.

tColor.IsBackground = true;

Additional Example

A slightly different example would be to have multiple threads trying to update the same value and see how they are interleaved... simple snippet to get the ball rolling.

private void btnStart_Click(object sender, EventArgs e)
{
  CreateBackgroundColorSetter(Color.Aqua);
  CreateBackgroundColorSetter(Color.Black);
  CreateBackgroundColorSetter(Color.DarkKhaki);
  CreateBackgroundColorSetter(Color.Green);
}


private void CreateBackgroundColorSetter(Color color)
{
  var thread = new Thread(() =>
                            {
                              while (true)
                              {
                                theLabel = color;
                                Thread.Sleep(100);
                              }
                            });
  thread.IsBackground = true;

  thread.Start();
}
Chris Baxter
  • 16,083
  • 9
  • 51
  • 72
3

you have 2 issues

a) you are not supposed to update the UI from other threads

b) even if you were allowed to do it you need to tell the UI to repaint

These are non trivial issues

If you are just experimenting with threading then use Debug.WriteLine to see what the background threads are doing

If you actually need to update the UI in the background then lookup BeginInvoke and InvokeNeeded

pm100
  • 48,078
  • 23
  • 82
  • 145
  • The code actually runs if you correct the ThreadTest.ChangeColor to not construct a new form. See example below. Typically you do need an invoke (and I was surprised that it wasn't required in this case). – Chris Baxter Nov 05 '10 at 15:06
1

If you really need to do threading in a GUI app you are going to need BackgroundWorker or something like it. As noted, other threads cannot update the GUI anyway so the sample shown there is a better model for moving long-running work items out of your main thread.

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • I agree that BackgroundWorker is a better way of handling this time of application, and ultimately will be required as you hit more complex examples, but the reason the code doesn't run is because of the Form1 foo = new Form1(); statement in ThreadTester.ChangeColor (see my answer). – Chris Baxter Nov 05 '10 at 15:23
  • @Calgary Coder - yes, this info was intended to be complementary to existing answers which relate to the proximate cause. – Steve Townsend Nov 05 '10 at 15:24
0

If you want do experiments with threading just create a console application and google "threading tutorial c#" to get some example.

Regarding threading and winform you can have a look at the below link just to have an idea about the consideration you should make before access win form property from another thread

In WinForms, why can't you update UI controls from other threads?

Community
  • 1
  • 1
Massimiliano Peluso
  • 26,379
  • 6
  • 61
  • 70