首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调用目标引发无效的跨线程操作异常

调用目标引发无效的跨线程操作异常
EN

Stack Overflow用户
提问于 2010-06-15 21:59:54
回答 3查看 677关注 0票数 0
代码语言:javascript
复制
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."

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

有什么想法吗?

EN

回答 3

Stack Overflow用户

发布于 2010-06-15 22:03:44

您正在更新创建UI控件的线程以外的线程上的UI控件。这是不允许的。

在常规代码中,可以使用Control.InvokeRequired属性。

假设你有一个有两个按钮和两个标签的表单,这里是如何从另一个线程进行更新的:

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2010-06-15 22:04:13

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

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

基本上,您需要在UI线程上执行此代码。

你为什么要通过反射而不是直接调用ShowContextMenu呢?您可能只需要类似于(假设C# 3)的内容:

代码语言:javascript
复制
MethodInvoker action = () => notify.ShowContextMenu();
someControl.Invoke(action);
票数 0
EN

Stack Overflow用户

发布于 2010-06-15 22:04:28

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3045845

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档