I get error Control accessed from a thread other than the thread it was created on
when I try to access WinForms control. I know that all modifications of contr
You must use BeginInvoke. If you need to get a value back (eg, the Text contents of the control), you may use EndInvoke to wait for completion.
That said, you may want to consider doing things the other way; have the GUI thread 'push' data over to background worker threads. This helps reduce the chance of racing against user input, and leads to a cleaner design with a clear separation of GUI and core logic.
For something as trivial as this, you don't have to use BeginInvoke specifically, you could use Invoke as well, but yes you do need to invoke the call on the UI thread. You can use some magic to hide the nasty details in a couple method calls and then use extension methods to make it cleaner. For example, let says I wanted to extend the TextBox control with a couple theadsafe methods for getting and setting the Text property. I might do something like this:
namespace System.Windows.Forms
{
public static class TextBoxExtensions
{
public static string GetTextThreadSafe(this TextBox box)
{
return GetTextBoxText(box);
}
public static void SetTextThreadSafe(this TextBox box, string str)
{
SetTextBoxText(box, str);
}
public static string GetTextBoxText(TextBox box)
{
if (box.InvokeRequired)
{
Func<TextBox, string> deleg = new Func<TextBox, string>(GetTextBoxText);
return box.Invoke(deleg, new object[] { box }).ToString();
}
else
{
return box.Text;
}
}
public static void SetTextBoxText(TextBox box, string str)
{
if (box.InvokeRequired)
{
Action<TextBox, string> deleg = new Action<TextBox, string>(SetTextBoxText);
box.Invoke(deleg, new object[] { box, str });
}
else
{
box.Text = str;
}
}
}
}
Then in another thread you could call the textbox like so:
Thread t = new Thread(new ThreadStart(() =>
{
// Threadsafe call to set the text
SomeTextBox.SetTextThreadSafe("asdf");
// Threadsafe call to get the text
MessageBox.Show(SomeTextBox.GetTextThreadSafe());
}));
t.IsBackground = true;
t.Start();