使用System.Window.Forms.Invoke(委托)从另一个表调用表单时发出问题

时间:2013-07-23 05:23:03

标签: c# .net multithreading winforms

我有两个表单和一个单例类。我正在使用formA的btn_A_Click中的单例类。

public partial class frmA : Form
{
    public frmA()
    {
        InitializeComponent();
        frmB frmB;
    }

    private void btn_A_Click(object sender, EventArgs e)
    {
        SessionMgmt.GetInstance().StartFormB(); 
    }
}

这是我的单例类,在这里我尝试使用Forms.Invoke()方法。

public class SessionMgmt
{
    static SessionMgmt _sessinMgr;
    frmB frB;

    private SessionMgmt()
    {
        frB = new frmB();
    }

    public static SessionMgmt GetInstance()
    {
        if (_sessinMgr != null)
            return _sessinMgr;
        else
        {
            _sessinMgr = new SessionMgmt();
            return _sessinMgr;
        }
    }

    public bool StartFormB()
    {
        frB.Invoke(new EventHandler(DisplayFrmB));
        return true;
    }

    private void DisplayFrmB(Object o, EventArgs e)
    {
        frB.Visible = true;
        frB.Refresh();
    }

}

这是我的表格。

public partial class frmB : Form
{
}

但是从frB.Invoke(new EventHandler(DisplayFrmB));方法引发了以下异常:

  

在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke。

我无法弄清楚这个问题,如果我遗漏了任何内容,请提供帮助或建议。

修改

以下结构是我当前项目显示下一个表单的方式。它是由VB.NET完成的,我需要在使用C#的新项目中使用类似的东西。我看到了Invoke函数,它指向一个事件,然后指向一个函数。在该函数中,它只使Form.Visible = true和Form.Refresh。但是为了理解我只是尝试了一个POc并遵循相同的步骤,但它还没有解决。

4 个答案:

答案 0 :(得分:2)

调用invoke的原因是什么?这不是为你做的工作吗?

public bool StartFormB()
{
    frB.Visible = true;
    return true;
}

答案 1 :(得分:0)

Windows窗体是Windows API的包装器,该异常意味着尚未创建基础窗口。我认为第一次将Visible设置为true时会创建它,还有其他几种情况可以实现。

请参阅此链接以获取可能的解决方案:http://blogs.msdn.com/b/mapo/archive/2011/04/27/forcing-handle-creation-in-a-net-windows-forms-control.aspx

答案 2 :(得分:0)

该异常有两个可能的原因:

  • 调用调用时不会创建表单
  • 你可能在错误的线程上创建控件

你应该在调用之前检查InvokeRequired属性,当然在那之前检查是否为

public bool StartFormB()
{
    if (frB == null)
    {
        throw new ArgumentNullException("frB");
    }

   if (frB.InvokeRequired)
   {

        frB.Invoke(new EventHandler(DisplayFrmB));
   }
   else
   {    
      if (frB.IsDisposed)
      {
        throw new ObjectDisposedException("Control is already disposed.");
      }
  }

  return true;
}

答案 3 :(得分:0)

如果控件的Visible属性为false,则不会创建控件句柄。当您调用Invoke时,您在委托中将控件可见状态设置为true,但尚未创建句柄,因此您无法调用Invoke。所以 - 你必须调用frB.CreateHandle(); after:frB = new frmB();强制创建控制句柄

    private SessionMgmt()
    {
        frB = new frmB();
        var h = frB.Handle;
    }