【问题标题】:Cross thread operation issue跨线程操作问题
【发布时间】:2013-11-18 10:45:47
【问题描述】:

我有一个场景,我必须将 Form 的一个实例调用为 ShowDialog()。 我的代码是这样的:

  Form view = ComponentFactory.GetInstance<IView>
                (viewConfig.Key) as Form;
  if (view == null)
  {
   if (_sysLog.IsErrorEnabled)
                _sysLog.Error("Invalid view configuration. Aborting!");
       throw new AbstractModelException("View not found.");
   }

  if (isFixed)
            view.FormBorderStyle = FormBorderStyle.FixedDialog;

   view.StartPosition = FormStartPosition.CenterScreen;
   view.ShowInTaskbar = false;
   view.FormClosed += new FormClosedEventHandler(OnViewClosed);
   view.FormClosing += new FormClosingEventHandler(OnViewClosing);

   if (view is IView)
   {
     InitializeView((IView)view);
     ((IView)view).Tag = tag;
   }

   if (parentWindow != null && parentWindow is IWin32Window)
            return view.ShowDialog(parentWindow as IWin32Window);
   return view.ShowDialog();

我已将引用从 .net 3.5 转换为 4.0。

 Error is:
  Cross-thread operation not valid: Control '' accessed from a thread other than the          
  thread it was created on.

这表明表单控件已经在 UI 线程中运行。

我已经尝试解决了

  if(view.InvokeRequired)
   {
     MethodInvoker method = new MethodInvoker(() => view.ShowDialog());
      DialogResult result = (DialogResult)view.Invoke(method);
    }

我已经尝试过 Invoke 和 BeginInvoke 两者。每次 InvokeRequired 在这里都是假的。

我也试过打电话给view.CreateControl,因为我可能在某些地方读到过
尚未创建表单控件并且未创建表单句柄。 但这也行不通。

ShowDialog 响应返回时每次都会出现错误。通过 ShowDialog 这个 打开表单并在表单关闭时处理后返回一个 对话结果。之后,这将返回到另一个调用当前函数的类。

请指导。

【问题讨论】:

  • 表单是在哪个线程上创建的creating 线程对 UI 控件很重要。这就是为什么您应该始终在 UI 线程上创建控件/表单...另外:所有控件是否都创建在 在同一个线程上
  • 没有任何线程。在这里,我们以 View 的形式打开表单。每个视图都添加到 app.config 文件中。当前代码是在 ViewManager.cs 中编写的,每个视图都是从其中打开的。
  • 如果你想更清楚,请告诉我

标签: c# .net winforms


【解决方案1】:

根据MSDN InvokeRequired 可以返回false 即使在InvokeRequired 应该是true 的情况下 - 即在您在该控件/表单的Handle 之前访问InvokeRequired 的情况下(或其父级)已创建。

基本上你的检查是不完整的,这会导致你看到的结果。

您需要检查IsHandleCreated - 如果是false,那么无论InvokeRequired 返回什么,您都需要使用Invoke/BeginInvoke

但是: 这通常不会有效地工作,因为 Invoke/BeginInvoke 检查哪个线程创建了 Handle 来发挥他们的魔力......

只有当IsHandleCreatedtrue 时,你才会根据InvokeRequired 返回的内容来行动——类似于:

if (control.IsHandleCreated)
{
    if (control.InvokeRequired)
    {
        control.BeginInvoke(action);
    }
    else
    {
        action.Invoke();
    }
}
else 
{ 
    // in this case InvokeRequired might lie - you need to make sure that this never happens! 
    throw new Exception ( "Somehow Handle has not yet been created on the UI thread!" );
}

因此,以下对于避免此问题很重要

始终确保Handle 在第一次访问 UI 线程以外的线程之前已创建。

根据MSDN,您只需在 UI 线程中引用 control.Handle 即可强制创建它 - 在您的代码中,这必须在您第一次从任何线程访问该控件/表单之前发生界面线程。

【讨论】:

  • 问题是......我们不能通过异常。该类被添加到在两个地方使用的项目中。一个是桌面应用程序,它工作正常,打开对话框和设置值非常好。其他地方是 Excel 加载项,从那里这个东西给出了错误。笑话是……对数据没有任何影响。数据库中的一切都很好,计算也很好。我们应该怎么做,使它不应该通过这个错误。
  • @Abhi 抱歉,但这是一个完全不同的问题......问题中的任何地方都没有提到 Office-/Excel-AddIns 并且没有足够的代码/信息来猜测发生了什么Excel 和您的插件之间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
相关资源
最近更新 更多