设置窗体的MdiParent属性会中断/阻止其Shown事件触发

本文关键字:Shown 事件 窗体 MdiParent 属性 中断 设置 | 更新日期: 2023-09-27 18:28:11

所以,我一直在stackoverflow和其他互联网论坛和知识库上搜索类似的主题,但到目前为止,我没有运气解决这个问题,我已经挣扎了整整一周。这是代码:

    private void matrículasToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Form1 form1 = new Form1();
        form1.Show();
        form1.MdiParent = this; // this == the main form of the aplication, wich has IsMdiParent property set to true.
    }

如果我去掉"form1.MdiParent=this",form1显示的事件将正常激发,执行其处理程序的所有内容,但如果我让它在那里,form1的显示事件将不会激发(我确实设置了断点,没有触发任何断点)。

奇怪的是,如果我使用Load事件而不是Shown,一切都很好,但我有点担心,如果将Shown替换为Load会破坏一些东西:(.

设置窗体的MdiParent属性会中断/阻止其Shown事件触发

试试这个代码

 Form1 form1 = new Form1();
 //Subscribe event here
 form1.MdiParent = this;
 form1.Show();

这对我有效

我不知道为什么你的代码不起作用,一旦我得到答案,我就会回来

编辑:我现在有答案了。

ISynchronizationInvoke's成员(InvokeBeginInvoke)由Control类实现如下。

  1. 获取创建窗口的线程的上下文
  2. 使用RegisterWindowMessage生成新窗口消息ID
  3. 将我们作为参数传递的委托封装在ThreadMethodEntry中,并将其添加到控件的内部Queue
  4. 将消息发布到线程的队列,消息ID由RegisterWindowMessage使用PostMessage返回
  5. Handles WndProc侦听messageId,然后对ThreadMethodEntry取消排队并调用委托

这里出了什么问题?

Form1 Form1=新Form1();form1.Show();form1.MdiParent=此;

Form.Show以某种方式导致对OnLoad方法的调用,即使用BeginInvoke 异步调用OnShown

if (base.IsHandleCreated)
{
    base.BeginInvoke(new MethodInvoker(this.CallShownEvent));//reflected code
}

因此,在发布的WindowMessage收到之前,您设置了form1.MdiParent = this;,这反过来又将控件强制为Destroy的句柄和ReCreate的新句柄。

DestroyHandle方法通过使用PeekMessage函数获取已发布的消息来吞咽该消息,然后枚举Queue中的所有元素,并将其状态设置为已完成,而不调用委托,而是将其标记为抛出ObjectDisposedException

Form1 form1 = new Form1();
form1.Show();
Action del = () =>
{
    Console.WriteLine("This will never be called");//our custom delegates too fails to be invoked
};
var res = form1.BeginInvoke(del);
//after some more code
form1.EndInvoke(res);//throws `ObjectDisposedException` which was marked previously
form1.MdiParent = this;

抛出ObjectDisposedException("Control")实际上是误导,不是吗?

注意:在form1.MdiParent = this;之前使用Application.DoEvents();可以很容易地解决此问题,因为DoEvents会立即处理所有挂起的消息。