2013-07-23 40 views
0

从另一个窗体调用问题我有两种形式和1个单例类。我在formA的btn_A_Click中初始化单例类。使用System.Window.Forms.Invoke(委托)

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(); 
    } 

}

这是我的formB。

public partial class frmB : Form 
{ 
} 

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

调用或BeginInvoke可直到窗口句柄已创建不能在一个控件调用。

我找不出这个问题,请帮助或建议我,如果我错过任何东西。

编辑

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

+0

您可以发布您尝试复制的最低vb.net代码吗? – YK1

回答

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; 
} 
+0

如果'InvokeRequired'为'false',调用'Invoke'实际上是没有害处的。 – Joel

+0

是的,阅读http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx –

+0

该页面说'InvokeRequired'可以返回'false'如果调用会发生在同一个线程上,或者如果句柄尚未创建。这只会在'IsHandleCreated'返回'false'的情况下有害。否则,它只是在同一个线程上进行调用。 'Invoke'几乎可以肯定是'SendMessage'的封装。鉴于这里的代码,句柄不会被创建。对'InvokeRequired'的调用将返回'false',并且表单将不会按需要显示。 – Joel

0

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

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

仍然是相同的问题 – kbvishnu

+0

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

+0

@AndriyVandych:'CreateHandle()'不是公共方法。但是你可以通过查询'Handle'属性来调用它''var h = frB.Handle;' – YK1

2

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

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

。但我需要使用Invoke – kbvishnu

+1

@VeeKayBee:你为什么需要使用'Invoke'? – YK1

+0

我倾向于同意。为什么你需要“调用”?该表单上该函数的唯一目的是确保您在创建窗体的线程上运行代码(因为窗口具有线程关联性,如果不这样,.NET将抛出异常)。但是如果你还没有创建表单,除非你从后台线程调用'StartFormB',否则你不能在错误的线程上运行。如果它只是从按钮点击处理程序调用,则表单A上运行的是同一线程。 – Joel