Reputation: 750
I'm writing chat client/server app with c# and I have problem with threading. I wrote this simple code for showing my problem.
I used thread_1 for showing Form but it just show it a second (maybe thread_1 terminated and closed the Form , but i IsAlive said its alive !). Thread_2 try to reach texBox that created on main Thread but it shows me:
"Cross-thread operation not valid: Control 'textBox2' accessed from a thread other than the thread it was created on."
I dont know how solve first problem but I solved second problem with BackgroundWorker but i like to do it with thread. Is there any way?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread t1;
Thread t2;
private void button1_Click(object sender, EventArgs e)
{
t1 = new Thread(doThread1);
t1.Name = "thread_1";
t2 = new Thread(doThread2);
t2.Name = "thread_2";
t1.Start();
t2.Start();
MessageBox.Show(t1.IsAlive.ToString());
}
private void doThread1()
{
Form frm2 = new Form();
frm2.Show();
}
private void doThread2()
{
try
{
for (int j = 10000; j > 0; j--)
textBox.Text = j.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Upvotes: 3
Views: 722
Reputation: 22352
As Linkerro mentioned, you want to take out the thread you call Thread 1 as your UI will already be in a thread when you start (all programs have a single main thread they start on). You were on the right track though, you want to put any long-running tasks on a separate thread so it doesn't block the UI. The only trick is you cannot directly maniuplate UI objects from background threads, they must be manipulated from the thread that owns them (which is the error message you are getting is saying).
Luckily there is a very easy way to accomplish this in .NET. In WPF you use UiComponent.Dispatcher.Invoke() and Winforms just use UiComponent.Invoke(). This allows your background thread to step over to the thread where the UI component lives to update it.
Invoke takes a delegate which represents the action you would like to run on the UI thread. In my example I pass in an action which is initialized using a lambada expression, taking no parameters and returning no value.
Try this
private void doThread2()
{
try
{
for (int j = 10000; j > 0; j--)
{
textBox.Invoke(new Action(() =>
textBox.Text = j.ToString()));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is a full example of how you can do this with Tasks. You will see while it is counting you can freely move the window around and it does not lock up. However take out the Task and leave the loop and you will see how the window freezes since the loop would then block the UI thread.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
for (int x = 0; x < 100000000; x++)
{
label1.Invoke(new Action(() =>
label1.Text = x.ToString()));
}
});
}
}
Upvotes: 2