跨线程操作问题

时间:2013-11-18 10:45:47

标签: c# .net winforms

我有一个场景,我必须将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这个 打开表单并在表单关闭后处理后返回a 的DialogResult。之后,这将返回到调用当前函数的另一个类。

请指导。

1 个答案:

答案 0 :(得分:2)

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

基本上,您的支票不完整会导致您看到的结果。

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

<强> BUT : 由于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!" );
}

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

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

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