C# 激活时MDI窗口z顺序异常

C# 激活时MDI窗口z顺序异常,c#,winforms,mdi,z-order,C#,Winforms,Mdi,Z Order,我有一个带有许多MDI子窗口的应用程序。通常,用户可以通过单击窗口的客户端和非客户端区域,将一个MDI子窗口带到前面。通常情况下,只要按下鼠标按钮,就会发生这种情况 现在,有时会发生的情况是,当用户单击其客户端区域上的MDI子窗体时,窗口不会像预期的那样出现在前面。但是,单击表单的标题栏确实会将窗口带到前面,但仅当鼠标按钮被释放时。这样做的效果是,用户可以将一个MDI子窗口拖到另一个MDI子窗口之后,当释放鼠标按钮时,被拖动的窗口会出现在前面 其效果是,如果我有几个MDI子窗口彼此部分重叠,我无

我有一个带有许多MDI子窗口的应用程序。通常,用户可以通过单击窗口的客户端和非客户端区域,将一个MDI子窗口带到前面。通常情况下,只要按下鼠标按钮,就会发生这种情况

现在,有时会发生的情况是,当用户单击其客户端区域上的MDI子窗体时,窗口不会像预期的那样出现在前面。但是,单击表单的标题栏确实会将窗口带到前面,但仅当鼠标按钮被释放时。这样做的效果是,用户可以将一个MDI子窗口拖到另一个MDI子窗口之后,当释放鼠标按钮时,被拖动的窗口会出现在前面

其效果是,如果我有几个MDI子窗口彼此部分重叠,我无法像通常那样将窗口置于前面。这似乎与焦点无关-一个MDI子窗口可以有焦点,但仍然位于另一个MDI子窗口的后面

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

我的问题分为两个部分:有什么想法可以解释为什么会发生这种情况,我如何调试我的程序来找出为什么会发生这种情况?

我怀疑窗口消息WM#u 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
00D209AA S WM\u PARENTNOTIFY fwEvent:WM\u LBUTTONDOWN XPO:146 YPO:147
00D209AA R WM_PARENTNOTIFY
00D209AA S WM_窗口位置更改lpwp:0012EE90
00D209AA R WM_窗口位置更改
00D209AA S WM_儿童激活
00D209AA S WM_NCPAINT hrgn:D3043A75
00D209AA R WM_NCPAINT
00D209AA S WM_擦除BKGND hdc:C20124F7
00D209AA S WM_GETTEXTLENGTH
00D209AA R WM_GETTEXTLENGTH cch:1
00D209AA S WM_GETTEXT cchTextMax:4 lpszText:0012DC48
00D209AA R WM_GETTEXT cchCopied:1 lpszText:0012DC48(“”)
00D209AA R WM_ERASEBKGND fErased:正确
00D209AA S WM_窗口位置更改lpwp:0012EB80
00D209AA R WM_窗口位置更改
00D209AA S WM_MDI激活hwndActivate:014809AE hwndActivate:00D209AA(激活)
00D209AA S WM_NCACTIVATE事实:正确
00D209AA R WM_n激活
00D209AA S WM\U IME\U SETCONTEXT fSet:1 iShow:C000000F
00D209AA R WM\U IME\U SETCONTEXT
00D209AA S WM_设置焦点hwndLoseFocus:00B20A2A
00D209AA R WM_设置焦点
00D209AA R WM\U MDI激活
00D209AA R WM_儿童激活
00D209AA S WM_WINDOWPOSCHANGED lpwp:0012EE90
00D209AA R WM_窗口位置已更改
00D209AA S WM_MOUSEACTIVATE hwndTopLevel:012C093A nHittest:HTCLIENT uMsg:WM_LBUTTONDOWN
00D209AA R WM_MOUSEACTIVATE FUACTIVE:MA_ACTIVE
当我在运行应用程序时得到重现bug的输出时,单击客户端区域会产生以下结果:

<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
023E0AA0 S WM\u事件:WM\u LBUTTONDOWN XPO:139 YPO:142
023E0AA0 R WM_PARENTNOTIFY
023E0AA0 S WM_MOUSEACTIVATE hwndTopLevel:012C093A nHittest:HTCLIENT uMsg:WM_LBUTTONDOWN
023E0AA0 R WM_鼠标激活FUACTIVE:MA_激活
查看消息编号,我可以立即看到有一堆消息没有出现,特别是,
WM\u CHILDACTIVATE

解决方案


在显示窗口之前,未设置其中一个窗体的父窗体

以下是一些可以尝试的建议:

  • 将单击事件添加到子窗体,然后单击call
    Show()
    将窗体置于最前面
  • 确保在所有子窗体上设置了
    mdipradent
    属性
  • 确保在父窗体上设置了
    IsMdiContainer
    属性
  • 将子窗体的
    WindowState
    设置为
    Normal
  • 使用
    Activate()
    激活表单并使其具有焦点
您还可以尝试利用父级的z顺序将焦点集中到子级:

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

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

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

您是否使用任何第三方UI库?(例如:DevExpress或Telerik或…)这些库通常使用pinvoke win32 API来实现一些漂亮的窗口和/或简洁的功能。如果您使用的是普通的旧winforms,那么最好了解一下

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

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


与此线程中当前的其他建议相反,您不应该对Mdi子级使用ShowDialog()。(我甚至希望,如果您尝试使用分配给窗体的MDI父级来显示对话框,Microsoft会抛出一个异常)。MDI儿童不允许成为模态窗口,这很可能导致您看到的不良行为。例如:一个表单希望成为模态/ontop,而一个普通的子表单试图获得焦点。

没有第三方UI库。是的,逐步完成加载过程(可能会跳过加载过程的一部分,看看是什么原因导致了错误)是我的想法,目前看来这是最好的方法。我只有一个保存文件,所以我不能做任何比较,真的。它也是一个二进制文件,所以我不能很容易地区分它。我会在有更多信息时更新