使用System.Window.Forms.Invoke(委托)从另一个窗体调用窗体时出现问题

本文关键字:窗体 调用 另一个 问题 Window System Forms Invoke 委托 使用 | 更新日期: 2023-09-27 18:24:39

我有两个表单和一个singleton类。我正在初始化formA的btn_A_Click中的singleton类。

public partial class frmA : Form
{
    public frmA()
    {
        InitializeComponent();
        frmB frmB;
    }
    private void btn_A_Click(object sender, EventArgs e)
    {
        SessionMgmt.GetInstance().StartFormB(); 
    }
}

这是我的singleton类,在这里我尝试使用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();
    }

}

这是我的表格B。

public partial class frmB : Form
{
}

但从frB.Invoke(new EventHandler(DisplayFrmB));方法中,它抛出以下异常:

在创建窗口句柄之前,不能对控件调用Invoke或BeginInvoke。

我搞不清楚这个问题,如果我遗漏了什么,请帮我或给我建议。

编辑

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

使用System.Window.Forms.Invoke(委托)从另一个窗体调用窗体时出现问题

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

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

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

该异常有两个可能的原因:
  • 调用invoke时未创建表单
  • 您可能在错误的线程上创建控件

在调用之前,您应该始终检查InvokeRequired属性,当然,在之前检查null

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;
}
如果控件的Visible属性为false,则不创建控件句柄。调用Invoke时,您在委托中将控件的可见状态设置为true,但句柄尚未创建,因此无法调用Invoke。因此,您必须调用frB.CreateHandle();after:frB=新frmB();强制创建控制手柄
    private SessionMgmt()
    {
        frB = new frmB();
        var h = frB.Handle;
    }