2010-06-15 117 views
0
MethodInfo mi = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic); 
mi.Invoke(notify, null); 

这引发以下异常:
{"Exception has been thrown by the target of an invocation."}调用目标投掷无效跨线程操作异常

用下面的内部异常:
"Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on."

如果我注释掉的代码行设置上下文菜单项的图像,然后停止抛出异常。

任何想法?

回答

0

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

您可能会产生混淆的MethodInfoInvoke方法,它只是调用了委托当前线程,Control.Invoke在UI线程上调用委托。

如果您尝试从正确的UI线程以外的线程访问UI元素,则会得到此异常。

基本上你需要在UI线程上执行这段代码。

是否有任何理由试图通过反射而不是直接调用ShowContextMenu?您可能只需要类似(假设C#3):

MethodInvoker action =() => notify.ShowContextMenu(); 
someControl.Invoke(action); 
+0

ShowContextMenu是非公开的,所以它必须通过反射? 它工作正常,如果我没有设置ToolStripItem图像。 另外,如果它是在ToolStripItem图像被设置之前执行的,那么即使在设置图像之后,它也会在程序持续时间内正确显示上下文菜单,而不会引发异常。 – sqwerty 2010-06-15 14:19:09

+1

@sqwerty:如果'ShowContextMenu'是非公开的,你根本不应该调用它。通过反思调用非公众成员只是要求麻烦 - 他们可以在不同版本之间进行更改。如果你真的想要这样做,那么只需使用'Control.Invoke'在正确的线程上完成它。它发生失败的确切情况无关紧要:您正在从非UI线程中触摸UI。不要这样做。 – 2010-06-15 15:33:01