Form.ShowDialog(IWin32Window) 应该与任何窗口句柄一起使用吗?
使用 System.Windows.Forms.ShowDialog(IWin32Window) 时,我是否应该能够传入表示任何窗口句柄的 IWin32Window 并使其相对于该窗口为模态?
作为 Internet Explorer 7 扩展的一部分,我尝试打开与 Internet Explorer 选项卡相关的窗口模式。 它不是当前选定的选项卡,但我可以获取该选项卡的 hwnd OK。 但是,当我将其传递给 ShowDialog 时,会显示我的表单,但它对于任何内容都不是模态的:我仍然可以在 Internet Explorer 中执行操作,包括在应该是所有者的选项卡中。 我的表单显示为浮动在 Internet Explorer 窗口上方,并且它保持在顶部,因此它不像只是作为普通表单打开,但它不是正确的模态。
使用 Spy++,我可以找到我的表单及其所有者句柄设置正确。
这是否意味着出了问题,或者我做错了什么? 如何使我的表单正确模式化?
仅供参考,我使用这个包装类从 hwnd
创建一个 IWin32Window
(感谢 Ryan!):
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
更新:使用 Internet Explorer 7 .NET 2.0
更新:使用 Spy++ 及其公开的句柄进行更多操作,我发现如果我使用不同的 hwnd
那么我可以使我的窗口成为选项卡的模式:
我正在使用选项卡的 < code>hwnd 按照 IWebBrowser2 的建议。 HWND doc,在 Spy++ 中显示为类 TabWindowClass
。 它有一个 Shell DocObject View
类的子级,而该类又具有 Internet_Explorer_Server 的子级。 如果我使用 Internet Explorer_Server
的 hwnd
那么它可以正常工作,例如,当我用鼠标单击其他选项卡时,Internet Explorer 会正常反应。 当我用鼠标单击感兴趣的选项卡时,它会播放 windows d'oh 声音,但不会执行任何操作。
我还不知道如何以编程方式获取 Internet_Explorer_Server hwnd
,但这应该是可能的。
另外,就其价值而言,在使用其他窗口句柄时,我通常能够使我的表单成为其他应用程序和对话框的模式。 所以我想我的问题的答案是“很多但不是所有句柄”......可能这取决于应用程序?
更新:另一个旁注:我想让我的表单模式化到选项卡而不是整个窗口的最初原因是,当从我的表单打开 MessageBox
时,将表单作为所有者传递,< code>MessageBox 并不总是在我的表单顶部打开。 如果刚刚打开新的 Internet Explorer 选项卡但未处于活动状态,则 MessageBox
将被隐藏,并且该选项卡将开始闪烁。 但是,由于 Internet Explorer 在我的表单打开模式下被禁用,因此无法切换到该选项卡,因此 Internet Explorer 将被冻结。 我认为打开选项卡的表单模式可以解决这个问题,但我发现另一个解决方案是避免使用 MessageBox
:如果我使用第二个表单和 ShowDialog(this) 从我的第一个表单中,然后第二个表单正确地打开到前面。 因此,在某些情况下,
Form.ShowDialog()
似乎比 MessageBox.Show()
效果更好。 更多讨论模式对话框和消息框的问题。
When using System.Windows.Forms.ShowDialog(IWin32Window)
, should I be able to pass in an IWin32Window
representing any window handle and have it be modal with respect to that window?
As part of an Internet Explorer 7 extension I'm trying to open a window modal with respect to an Internet Explorer tab. It's not the currently selected tab, but I can get the hwnd of the tab OK. However, when I pass this to ShowDialog my Form is shown, but it's not modal with respect to anything: I can still do things in Internet Explorer, including in the tab that's supposed to be the owner. My form is shown floating above the Internet Explorer windows and it stays on top, so it's not like it's just opened as a normal form, but it's not correctly modal.
Using Spy++, I can find my form and it's owner handle is correctly set.
Does this mean that something has gone wrong, or I'm doing something wrong? How do I make my form correctly modal?
FYI, I'm using this wrapper class to create an IWin32Window
from a hwnd
(thanks Ryan!):
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
UPDATE: Using Internet Explorer 7 & .NET 2.0
UPDATE: Playing around some more with Spy++ and the handles it exposes, I find that if I use a different hwnd
then I can make my window modal to the tab:
I was using the tab's hwnd
as suggested by the IWebBrowser2.HWND doc, which in Spy++ appears as class TabWindowClass
. It has a child of class Shell DocObject View
, which has a child of Internet_Explorer_Server. If I use the hwnd
of the Internet Explorer_Server
then it works correctly, for example, when I click with the mouse on other tabs, Internet Explorer reacts normally. When I click with the mouse on the tab of interest, it plays the windows d'oh sound and doesn't do anything.
I don't yet know how to programatically get the Internet_Explorer_Server hwnd
, but it should be possible.
Also, for what it's worth, while playing with other window handles I was generally able to make my form modal to other applications and dialogs. So I guess the answer to my question is 'many but not all handles'... possibly it depends on the application?
UPDATE: Another side-note: The original reason I wanted to make my form modal to the tab instead of the whole window is that when opening a MessageBox
from my form, passing the form as owner, the MessageBox
would not always open on top of my form. If a new Internet Explorer tab had just been opened but wasn't active then the MessageBox
would be hidden and that tab would start flashing. However, since Internet Explorer was disabled with my form opened modal it wasn't possible to switch to that tab, so Internet Explorer would be frozen. I thought that opening my form modal to the tab would solve this, but I've found another solution is to avoid using MessageBox
: if I use a second form and ShowDialog(this)
from my first form then the second form correctly opens to the front. So it seems that Form.ShowDialog()
works better than MessageBox.Show()
in some cases. More discussion in Problems with modal dialogs and messageboxes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
ShowDialog() 做了两件重要的事情。 它开始泵送消息循环,以便它以模态方式作用于调用代码。 它还通过 EnableWindow(false) API 调用禁用应用程序中的任何其他窗口。 后者是你的情况没有发生的情况。 考虑到需要禁用的窗口不是 WF 窗口,这并不完全令人惊讶。
您可能需要自己调用EnableWindow()。 请务必在对话框关闭之前重新启用它,否则 Windows 将寻找另一个应用程序的窗口来获取焦点。
ShowDialog() does two important things. It starts pumping a message loop so it acts modally to the calling code. And it disables any other windows in the application with a EnableWindow(false) API call. The latter is what is not happening in your case. Not entirely surprising, considering that the window that needs to be disabled is not a WF window.
You may need to call EnableWindow() yourself. Be sure to re-enable it in before the dialog closes or Windows will go hunting for another app's window to give the focus to.
你的代码是正确的。 您可能遇到的问题是 IE 有一个与其选项卡相关的线程模型。 我不知道确切的细节,但简短的版本是每个选项卡可以并且可能在与其他选项卡不同的线程上运行。
对话框的模态性特定于对话框运行的线程。 其他线程上的 UI 将不受另一个线程上的模型对话框的影响。 由于这个原因,您完全有可能访问在不同线程上运行的选项卡。
Your code is correct. The problem you are likely running into though is that IE has a threading model related to its tabs. I don't know the exact details but the short version is that each tab can and likely is running on a different thread than other tabs.
The Modal'ness of a dialog is specific to the thread where the dialog is running. UI on other threads will be unaffected by a model dialog on another thread. It's entirely possible you are able to access tabs which are running on a different thread for this reason.
下面是 Ryan/Rory 的 WindowWrapper 代码的更简洁版本:
Here's a more concise version of Ryan/Rory's WindowWrapper code:
我从未在 IE 扩展中尝试过此操作,但我有预感,IE 可能不会“尊重”Win32 样式的模式窗口,就像它使用 window.open().< 从 Javascript 引发的模式窗口一样。 /code>
您是否针对 IE 以外的其他程序测试过此代码,只是为了确认它是否能像其他应用程序一样工作?
I have never tried this from an IE extension, but I have a hunch that IE may not "respect" a Win32-style modal window the same way it does a modal window raised from Javascript using
window.open().
Have you tested this code against something other than IE, just to confirm it works the way it should for other applications?
这是 .NET 中的内置解决方案:
public static NativeWindow FromHandle(IntPtr handle)
here is a build in solution in .NET:
public static NativeWindow FromHandle(IntPtr handle)