c# - Form.Show()导致Visual Studio 2010中的InvalidOperationException,该异常在2008年不存在

标签 c# multithreading visual-studio-2008 visual-studio-2010

我有一些采用表单​​对象(winforms)并在专用线程上调用form.Show()的代码(它旋转一个新线程)。
在Visual Studio 2008(框架3.5)中,此功能运行良好。我现在迁移到2010,但失败了
“InvalodOperationException:“跨线程操作无效:控件”是从创建该线程的线程之外的其他线程访问的。”

(当然,我们的一半文件已 checkout 进行迁移,整个团队正在等待...)

这是一些代码(这是正在运行的代码,因此让我迷失了一些冗余的详细信息):

    private void ShowForm(object container)
    {
        FormContainer formContainer = (FormContainer)container;
        Process sboProcess = GetSboProcess();
        if (sboProcess != null)
        {
            WindowWrapper MyWindow = new WindowWrapper(sboProcess.MainWindowHandle);
            if (formContainer.ShowDialog)
            {
                formContainer.Form.ShowDialog(MyWindow);
            }
            else
            {
                //formContainer.Form.Invoke((MethodInvoker)delegate() { formContainer.Form.Show(MyWindow); });
                formContainer.Form.Show(MyWindow);
                //Run thread while form is opened:
                System.Windows.Forms.Application.Run(formContainer.Form);
            }
        }
    }



public class FormContainer
{
    private readonly Form form;
    private readonly bool showDialog;

    public FormContainer(Form form, bool showDialog)
    {
        this.form = form;
        this.showDialog = showDialog;
    }

    public bool ShowDialog
    {
        get { return showDialog; }
    }

    public Form Form
    {
        get { return form; }
    }

}

 public class WindowWrapper : IWin32Window
{
    private readonly IntPtr handle;

    public WindowWrapper(IntPtr handle)
    {
        this.handle = handle;
    }

    #region Implementation of IWin32Window

    /// <summary>
    ///                     Gets the handle to the window represented by the implementer.
    /// </summary>
    /// <returns>
    ///                     A handle to the window represented by the implementer.
    /// </returns>
    /// <filterpriority>1</filterpriority>
    public IntPtr Handle
    {
        get { return handle; }
    }

    #endregion
}

有人有主意吗?

谢谢,

阿舍尔

最佳答案

用一句话专用线程必须回调拥有该表单的UI线程。跨线程UI操作是非法的,因为某些操作可能导致所涉及的UI控件与Windows消息泵分离。这是一件坏事,因为Windows无法告诉窗口执行任何操作,包括绘制自身,移动甚至关闭。窗口变为“流氓”,并且所有Windows可以做的就是终止产生该窗口的整个过程。

form方法的调用可以是同步操作,也可以是异步操作,但是无论哪种方式,都必须排队等待它才能由UI线程运行。

这是一种从后台线程SEEM进行调用的方法,就像它们由后台线程执行一样,而不会违反跨线程规则:

//in your form class
public new void Show()
{
   if(!InvokeRequired)
      base.Show();
   else
      this.Invoke((MethodInvoker)(()=>base.Show()));
}

了解您不能将表单作为其基类System.Windows.Form来处理;它必须是您创建的具体表单类。否则,将忽略方法隐藏,并且默认情况下使用基本实现。

通过这种方式进行设置,每当某个操作可能要从后台线程运行时,就可以避免跨线程操作。如果需要,可以通过在控件上调用BeginInvoke()而不是Invoke()来将此方法更改为异步运行,但是由于对Show()的调用通常会同步运行,因此我会坚持使用Invoke。

关于c# - Form.Show()导致Visual Studio 2010中的InvalidOperationException,该异常在2008年不存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6257434/

相关文章:

asp.net - Visual Studio "Unable to start debugging on the web server. The web server did not respond in a timely manner."

c# - .Net程序集的文档报告

c++ - 使用boost的多线程一位读者和一位作者

java - JAVA 中的守护进程线程组是什么?

c++ - qt类中的线程

vb.net - 在 Visual Studio 2008 中禁用 Visual Basic 后台编译器

c++ - 我在 Visual Studio 2008 中看不到俄语字母表

c# - 初始加载后取消选择列表框中的所有项目

c# - 为什么我不能将具体类型列表分配给该具体接口(interface)的列表?

c# - 在 Windows Mobile C# 项目中将文件上传到服务器