调用目标抛出无效的跨线程操作异常

时间:2010-06-15 13:59:54

标签: c# .net

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."

如果我注释掉一行代码来设置上下文菜单条目的图像,那么它就会停止抛出异常。

有什么想法吗?

3 个答案:

答案 0 :(得分: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);
     }
   }

答案 1 :(得分:0)

您可能会混淆Invoke MethodInfo方法,它只调用当前线程上的委托,Control.Invoke调用UI线程上的委托。

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

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

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

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

答案 2 :(得分:0)

您无法从非UI线程调用UI方法。我建议使用TaskScheduler.FromCurrentSynchronizationContext封送对UI线程的调用。