2011-04-12 76 views
4

我得到下面的異常在Windows窗體應用程序何時註冊將調用Form.Invoke到事件的方法?

System.InvalidOperationException:調用或BeginInvoke可直到窗口句柄已創建不能在一個控件調用。

發生異常的方法調用this.Invoke(System.Windows.Forms.Form.Invoke)。此方法在構造函數中註冊到另一個類的事件,這似乎會導致競爭條件和此異常。

public Form1() 
{ 
    InitializeComponent(); 
    SomeOtherClass.Instance.MyEvent += new SomeDelegate(MyMethod); 
} 

private void MyMethod() 
{ 
    this.Invoke((MethodInvoker)delegate 
    { 
     // ... some code ... 
    } 
} 

表單生命週期的哪個階段是Handle創建的?在哪種形式的事件中,將該方法註冊到外國事件中是否安全?

+3

它看起來像你不是在你的構造函數調用的InitializeComponent()。 – bitxwise 2011-04-12 10:32:09

+2

有** HandleCreated **事件表單,您可能會檢查, – V4Vendetta 2011-04-12 10:51:55

+0

@bitxwise,我在構造函數中首先調用InitializeComponent,我只是將它從代碼示例中簡單地刪除...我將再次添加它。 – Hinek 2011-04-12 11:38:24

回答

2

好吧,我現在把它改成這樣:

public Form1(){ 
    InitializeComponent(); 
} 
protected override void OnHandleCreated(EventArgs e) 
{ 
    base.OnHandleCreated(e); 
    SomeOtherClass.Instance.MyEvent += new SomeDelegate(MyMethod); 
} 
private void MyMethod() 
{ 
    this.Invoke((MethodInvoker)delegate 
    { 
     // ... some code ... 
    } 
} 

的替代版本是

public Form1(){ 
    InitializeComponent(); 
    SomeOtherClass.Instance.MyEvent += new SomeDelegate(MyMethod); 
} 
private void MyMethod() 
{ 
    if (this.IsHandleCreated) 
    { 
     this.Invoke((MethodInvoker)delegate 
     { 
      // ... some code ... 
     } 
    } 
} 
+0

您的替代版本不是一個更乾淨的解決方案,因爲每次事件觸發冗餘檢查是否創建句柄。 – crypted 2011-04-12 12:08:31

+0

因此我選擇了第一個版本;-) – Hinek 2011-04-12 12:54:13

+0

不要忘記選擇一個最適合您需要的答案;-)。 – crypted 2011-04-12 13:54:36

2

我想如果你在OnShow事件中註冊方法,你應該是安全的。

+0

感謝您的回答。你是在想這個還是有事實/來源來支持你的意見? – Hinek 2011-04-12 11:40:26

+0

@Hinek:當OnShow事件上升時,表單首次顯示,因此每個圖形句柄都已創建。我不能說我確定它能正常工作,因爲我現在無法測試它,但我很確定... – Marco 2011-04-12 11:46:09

+0

@Hinek:如果在OnShown()事件中檢查this.IsHandleCreated,你會發現它是真的 – Marco 2011-04-12 13:41:30

2

將在InitializeComponent()調用回你註冊的處理程序之前,通過bitxwise

當表單配置unregsiter處理程序,然後你會得到同樣的問題的建議。

您可以在您的處理程序中執行諸如if(this.IsHandleCreated)之類的操作,以確保安全。

+0

我已經調用了InitializeComponent並註銷了處理程序,我只是想在代碼中儘可能簡單地顯示代碼。 – Hinek 2011-04-12 11:37:22

0

正如大家所提到的IsHandleCreated是要走的路。 以下片段告訴你如何做到這一點。

public class TestEvent : Form 
{ 

    protected override void OnHandleCreated(EventArgs e) 
    { 
     base.OnHandleCreated(e); 
     MyMethod(); 

    } 
    private void MyMethod() 
    { 

     this.Invoke(new Action(() => 
            { 
             //Here goes your code. 
            })); 
    } 
} 
+0

對不起,但你的代碼也沒有任何意義,你也沒有使用IsHandleCreated,正如你之前提到的那樣... – Hinek 2011-04-12 11:55:11

+0

確定這個方法將在剛剛創建句柄之後被調用。保護覆蓋無效OnHandleCreated(EventArgs e) – crypted 2011-04-12 12:01:07