【问题标题】:MDI window z-order oddity when activating激活时 MDI 窗口 z 顺序异常
【发布时间】:2011-10-16 20:32:43
【问题描述】:

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

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

效果是,如果我有几个 MDI 子窗口相互部分重叠,我就不能像往常一样把一个窗口放在前面。这似乎与焦点无关 - MDI 子窗口可以有焦点,但仍另一个 MDI 子窗口之后。

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

我的问题分为两部分:知道为什么会发生这种情况,以及如何调试我的程序以找出发生这种情况的原因?

我怀疑窗口消息 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 未设置其中一种表单在显示窗口之前

【问题讨论】:

    标签: c# winforms mdi z-order


    【解决方案1】:

    以下是一些尝试的建议:

    • 向子窗体添加点击事件,点击时调用Show() 将窗体置于最前面
    • 确保在所有子窗体上设置MdiParent 属性
    • 确保在父表单上设置IsMdiContainer 属性
    • 将子窗体的WindowState 设置为Normal
    • 使用Activate() 激活表单并赋予其焦点

    您也可以尝试利用父级的 z 顺序将焦点放在子级:

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

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

    【讨论】:

    • 在没有设置 MdiParent 的情况下创建了一个窗口。正如本建议的那样,您可能会编辑您的答案,因为 ShowDialog() 不正确,我不认为。
    • 如果我的建议解决了您的问题,为什么我没有得到赏金?我很困惑...
    • 两个答案都很有帮助。虽然您的答案包含结果是 正确 的答案,但 Ben 的答案通过建议一种方法来找到问题的根本原因(这是原始问题的一部分)对我的帮助更大。我想在你们之间分配赏金,但他的回答帮助我真正解决了问题。对于从现在几个月(或几年)后查看此问题的其他人,您的答案更合适,因此绿色复选标记。
    • 很公平。我对此有点沮丧,但我明白你来自哪里:)
    【解决方案2】:

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

    您是否在使用任何第三方 UI 库? (例如:DevExpress 或 Telerik 或 ...)这些库通常使用 pinvoke win32 api 来实现一些外观精美的窗口和/或简洁的功能。如果您使用的是普通的旧 winform,那会很高兴。

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

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

    与此线程上当前的其他建议相反,您不应将 ShowDialog() 用于 Mdi Children。 (如果您尝试使用分配给表单的 MdiParent 来显示对话框,我什至希望 Microsoft 抛出异常)。 MdiChildren 不允许成为模态窗口,这很可能会导致您看到的那种不良行为。例如:一个表单想要成为模态/置顶,而一个普通的子表单试图获得焦点。

    【讨论】:

    • 没有第三方 UI 库。是的,逐步完成加载过程(并可能跳过部分加载过程以查看导致错误的原因)是我的一个想法,目前,这似乎是最好的方法。我只有一个保存文件,所以我无法进行任何比较,真的。它也是一个二进制文件,所以我不能轻易区分它。当我有更多信息时,我会更新。
    • 逐步完成加载过程,我能够识别出一个 MDI 子节点在在设置 MdiParent 之前之前显示的位置。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多