當我嘗試訪問WinForms控件時,出現錯誤Control accessed from a thread other than the thread it was created on
。我知道所有的控件修改應該在UI線程中執行(需要BeginInvoke()
等),但是我需要我的控件是隻讀的。WinForms線程安全控制訪問
這裏是我的簡化代碼:
string text = textBox.Text;
什麼是從另一個線程訪問的WinForms控件的屬性值的模式?
當我嘗試訪問WinForms控件時,出現錯誤Control accessed from a thread other than the thread it was created on
。我知道所有的控件修改應該在UI線程中執行(需要BeginInvoke()
等),但是我需要我的控件是隻讀的。WinForms線程安全控制訪問
這裏是我的簡化代碼:
string text = textBox.Text;
什麼是從另一個線程訪問的WinForms控件的屬性值的模式?
你必須使用BeginInvoke。如果需要返回值(例如,控件的文本內容),則可以使用EndInvoke等待完成。
這就是說,你可能想考慮用另一種方式做事;讓GUI線程將數據推送到後臺工作線程。這有助於減少與用戶輸入競爭的機會,並導致更清晰的GUI和核心邏輯分離的設計。
對於像這樣微不足道的事情,您不必特意使用BeginInvoke,也可以使用Invoke,但是您需要在UI線程上調用該調用。您可以使用一些魔法來隱藏幾個方法調用中令人討厭的細節,然後使用擴展方法使其更清晰。例如,讓我說我想擴展TextBox控件與一對夫婦獲取和設置Text屬性的方法。我可能會做這樣的事情:
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;
}
}
}
}
然後在另一個線程你可以調用文本框,如下所示:
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();