您正在更新創建它們的線程以外的線程上的UI控件。這是不允許的。
在常規代碼中,您可以使用Control.InvokeRequired屬性。
假設你有兩個按鈕的形式,這裏兩個標籤是如何從另一個線程做更新:
private void button1_Click(object sender, EventArgs e)
{
//force execution on another thread
new Thread(updateLabelThreaded).Start();
}
private void button2_Click(object sender, EventArgs e)
{
//force execution on another thread
new Thread(updateLabelReflect).Start();
}
private void updateLabelThreaded()
{
if (!label1.InvokeRequired)
{
//if we are on the correct thread, do a trivial update
label1.Text = "something";
}
else
{
//else invoke the same method, on the UI thread
Invoke(new Action(updateLabelThreaded), null);
}
}
private void updateLabelReflect()
{
Control ctrl = label2;
PropertyInfo pi = typeof (Label).GetProperty("InvokeRequired");
bool shouldInvoke = (bool) pi.GetValue(ctrl, null);
if (!shouldInvoke)
{
//if we are on the correct thread, reflect whatever is neccesary - business as usual
PropertyInfo txtProp = typeof (Label).GetProperty("Text");
txtProp.SetValue(ctrl, "Something 2", null);
}
else
{
//else invoke the same method, on the UI thread
Invoke(new Action(updateLabelReflect), null);
}
}
ShowContextMenu是非公開的,所以它必須通過反射? 它工作正常,如果我沒有設置ToolStripItem圖像。 另外,如果它是在ToolStripItem圖像被設置之前執行的,那麼即使在設置圖像之後,它也會在程序持續時間內正確顯示上下文菜單,而不會引發異常。 – sqwerty 2010-06-15 14:19:09
@sqwerty:如果'ShowContextMenu'是非公開的,你根本不應該調用它。通過反思調用非公衆成員只是要求麻煩 - 他們可以在不同版本之間進行更改。如果你真的想要這樣做,那麼只需使用'Control.Invoke'在正確的線程上完成它。它發生失敗的確切情況無關緊要:您正在從非UI線程中觸摸UI。不要這樣做。 – 2010-06-15 15:33:01