2011-04-12 74 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