激活时MDI窗口z次奇怪

时间:2011-10-16 20:32:43

标签: c# winforms mdi z-order

我有一个带有许多MDI子窗口的应用程序。通常,用户可以通过单击窗口的客户端和非客户端区域将一个MDI子窗口置于前面。这似乎通常在鼠标按钮关闭时发生。

现在,有时发生的事情是,当用户在其客户区域上单击MDI子表单时,窗口会按预期到达前面。但是,单击窗体的标题栏会将窗口置于前面,但仅在释放鼠标按钮时才会显示。这样的效果是用户可以将一个MDI子窗口拖到另一个窗口后面,当释放鼠标按钮时,拖动的窗口就会出现在前面。

效果是,如果我有几个MDI子窗口彼此部分重叠,我不能像往常一样将窗口带到前面。这似乎与焦点无关 - MDI子窗口可以具有焦点,但仍然后面的另一个MDI子窗口。

此外 - 这似乎是在使用应用程序一段时间后随机发生的。我可以使用从用户发送的序列化程序状态(“保存”文件)来重现该错误。

我的问题有2个部分:为什么会发生这种情况的任何想法,以及如何调试我的程序以找出发生这种情况的原因?

我怀疑窗口消息WM_ACTIVATE(或类似的东西)没有被正确处理,但这是一个C#应用程序,我没有对消息队列做任何异常。

编辑:这是spy ++的一些额外信息。

当一切正常发生时,下面是spy ++的输出:

<00013> 00D209AA S WM_PARENTNOTIFY fwEvent:WM_LBUTTONDOWN xPos:146 yPos:147
<00014> 00D209AA R WM_PARENTNOTIFY
<00015> 00D209AA S WM_WINDOWPOSCHANGING lpwp:0012EE90
<00016> 00D209AA R WM_WINDOWPOSCHANGING
<00017> 00D209AA S WM_CHILDACTIVATE
<00018> 00D209AA S WM_NCPAINT hrgn:D3043A75
<00019> 00D209AA R WM_NCPAINT
<00020> 00D209AA S WM_ERASEBKGND hdc:C20124F7
<00021> 00D209AA S WM_GETTEXTLENGTH
<00022> 00D209AA R WM_GETTEXTLENGTH cch:1
<00023> 00D209AA S WM_GETTEXT cchTextMax:4 lpszText:0012DC48
<00024> 00D209AA R WM_GETTEXT cchCopied:1 lpszText:0012DC48 (" ")
<00025> 00D209AA R WM_ERASEBKGND fErased:True
<00026> 00D209AA S WM_WINDOWPOSCHANGING lpwp:0012EB80
<00027> 00D209AA R WM_WINDOWPOSCHANGING
<00028> 00D209AA S WM_MDIACTIVATE hwndDeactivate:014809AE hwndActivate:00D209AA (activating)
<00029> 00D209AA S WM_NCACTIVATE fActive:True
<00030> 00D209AA R WM_NCACTIVATE
<00031> 00D209AA S WM_IME_SETCONTEXT fSet:1 iShow:C000000F
<00032> 00D209AA R WM_IME_SETCONTEXT
<00033> 00D209AA S WM_SETFOCUS hwndLoseFocus:00B20A2A
<00034> 00D209AA R WM_SETFOCUS
<00035> 00D209AA R WM_MDIACTIVATE
<00036> 00D209AA R WM_CHILDACTIVATE
<00037> 00D209AA S WM_WINDOWPOSCHANGED lpwp:0012EE90
<00038> 00D209AA R WM_WINDOWPOSCHANGED
<00039> 00D209AA S WM_MOUSEACTIVATE hwndTopLevel:012C093A nHittest:HTCLIENT uMsg:WM_LBUTTONDOWN
<00040> 00D209AA R WM_MOUSEACTIVATE fuActivate:MA_ACTIVATE

当我从运行应用程序获得输出并重现错误时,单击客户区会产生以下结果:

<01315> 023E0AA0 S WM_PARENTNOTIFY fwEvent:WM_LBUTTONDOWN xPos:139 yPos:142
<01316> 023E0AA0 R WM_PARENTNOTIFY
<01317> 023E0AA0 S WM_MOUSEACTIVATE hwndTopLevel:012C093A nHittest:HTCLIENT uMsg:WM_LBUTTONDOWN
<01318> 023E0AA0 R WM_MOUSEACTIVATE fuActivate:MA_ACTIVATE

查看消息编号,我可以立即看到有大量消息未发生,具体而言,WM_CHILDACTIVATE

解决方案

其中一个表单的

MdiParent未在窗口显示之前设置

2 个答案:

答案 0 :(得分:3)

以下是一些尝试的建议:

  • 将单击事件添加到子表单,然后单击调用Show()将表单放到前面
  • 确保在所有子表单上设置了MdiParent属性
  • 确保在父表单上设置了IsMdiContainer属性
  • 将子表单的WindowState设置为Normal
  • 使用Activate()激活表单并将其设为焦点

您还可以尝试利用父级的z顺序为孩子提供焦点:

this.ActiveMdiChild.SendToBack();
Control.ControlCollection ct = ((MdiClient)this.ActiveMdiChild.Parent).Controls;
((Form)ct[0]).Activate();

希望这些建议中的一项或多项能解决您的问题。

答案 1 :(得分:1)

这个问题的答案可能比您分享的应用程序的实现更深入。

您使用的是第三方UI库吗? (例如:DevExpress或Telerik或......)这些库经常使用pinvoke win32 apis来实现一些漂亮的皮肤窗口和/或整洁的功能。如果你使用普通的老式winforms,那就太好了。

您可以使用已保存的应用程序状态重现该问题,这表明子窗口的创建方式存在错误。我将逐步加载这个保存的状态文件,以查看是否所有子窗口都以相同的方式加载。这种问题很可能归结为某一行代码。

此外,如果您可以收集多个已保存的状态文件来重现该问题,您可以识别趋势。也许它是您应用程序中的一个特定窗口,它始终显示上述行为?

与此线程中的其他建议相反,您不应对Mdi Children使用ShowDialog()。 (如果你试图将ShowDialog与MdiParent一起分配给表单,我甚至希望微软抛出异常)。 MdiChildren不允许是模态窗口,这很可能导致你看到的那种不良行为。例如:一个表格想要模态/ ontop而普通的儿童表格试图获得焦点。