2013-07-23 85 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