using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace testThreads
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void countToLots()
{
for (int i = 0; i < 10000000; i++)
{
textBox1.Text = "Counting to 10000000, value is " + i + Environment.NewLine;
}
}
public void c开发者_开发知识库ountToZero()
{
for (int i = 10000000; i > 0; i--)
{
textBox2.Text = "Counting to 0, value is " + i + Environment.NewLine;
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread countUp = new Thread(new ThreadStart(countToLots));
Thread countDown = new Thread(new ThreadStart(countToZero));
countUp.Start();
countDown.Start();
}
private void button2_Click(object sender, EventArgs e)
{
textBox3.Text = "Bobby bob bob " + Environment.NewLine;
}
}
}
I really need to try and get the hang of this - i just dont understand the theory behind why i get an error message. Could someone help me out please?
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
UI controls have "thread affinity"; they do not want to be touched by anything except the UI thread; that includes reading and writing properties. The assignment to .Text
should be done from the UI thread, either by using Invoke
, or BackgroundWorker
.
For example:
public void countToLots()
{
for (int i = 0; i < 10000000; i++)
{
// running on bg thread
textBox1.Invoke((MethodInvoker) delegate {
// running on UI thread
textBox1.Text = "Counting to 10000000, value is "
+ i + Environment.NewLine;
});
// running on bg thread again
}
}
But note that this type of thread switching has overhead. You should not call back every iteration - you should (for example) update the UI every [n] iterations - in the above, every 10000 for example.
You cannot use a method or property of a Form control from a different thread than the thread that created (called new) the control.
To do that just do:
public void countToLots()
{
for (int i = 0; i < 10000000; i++)
{
SetText("Counting to 10000000, value is " + i + Environment.NewLine);
}
}
public void SetText(string text)
{
if (this.textBox1.InvokeRequired())
{
Action<string> auxDelegate = SetText;
this.BeginInvoke(auxDelegate,text);
}
else
{
this.textBox1.Text = text;
}
}
What the method is doing with the beginInvoke is just calling again the SetText method from the thread that created the control.
Ok, about the theory behind WHY controls have UI Thread affinity.
If you've programmed long enough you would remember the days when forms and rapid application development were not the standard. In those days just droping a control into a form was rare... everything was done by the old school.
Now, in windows, the "old school" way of doing things involved defining a WindowProc.
The WindowProc is a function which is invoked to handle application message (notice I say is, not was). This function runs on the main program thread and is in charge of handling every message the application receives, including user interface paint and refresh.
Nowadays all that is mostly automated so that when you create a form the code in charge of doing all the work is autogenerated and you don't have to worry about that... but it is still there.
Of course, if the thread in charge of drawing the user interface with all its controls, is the main thread, you'll see how changing things from another thread might disturb the application itself with race conditions and so on. In addition, since the UI handling is autogenerated you can't just put the synchronization mechanisms that you'll use with two standard threads because you only have access to code on one thread, yours, but not to the main windowproc callback.
In a way, what BeginInvoke will do for you is pass a message to the main thread telling it to kindly handle the delegate in her own context when the time is right, thus delegating the execution to the main thread.
精彩评论