您正在更新创建它们的线程以外的线程上的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