gpt4 book ai didi

c# - MessageBox模态到单一形式

转载 作者:行者123 更新时间:2023-11-30 16:54:28 54 4
gpt4 key购买 nike

我想显示一个 MessageBox,它仅对单个表单具有模态,并允许线程上的其他顶级窗口保持事件状态。 WinForms 禁用当前线程上的所有窗口,无论是显示自定义模式窗体还是使用 MessageBox 类。

我已经尝试了多种不同的方法来解决这个问题,包括重新启用任何其他顶级窗口(使用 Win32 EnableWindow 函数)和 p/调用 native MessageBox 功能。这两种方法都有效,但键盘快捷键无法操作,包括在控件之间移动的选项卡、退出以取消打开的菜单以及最重要的菜单快捷键。

我可以通过在显示 MessageBox 时安装键盘 Hook 然后在事件窗体上直接调用 ProcessCmdKey 来使菜单快捷键工作,但其他键盘快捷键仍然不起作用工作。我想我可以继续并添加更多 hack 来使这些其他案例起作用,但我想知道是否有更好的方法。

注意,这与being non-blocking无关,但关于不禁用当前线程上的所有窗口。然而,碰巧解决方案可能是相似的。

最佳答案

您在这里遇到的基本问题是 MessageBox.Show() 抽取自己的消息循环以使自己成为模态。此消息循环内置于 Windows 中,完全不知道 Winforms 消息循环是什么样的。因此,当您使用 MessageBox 时,Winforms 在其消息循环中所做的任何特殊操作都不会发生。这是键盘处理:检测助记符、实现导航和调用 ProcessCmdKey() 等方法,以便表单可以实现自己的快捷键击。通常不是问题,因为它应该是模态的并且忽略用户输入。

恢复此功能的唯一实用方法是在其自己的线程中显示消息框。这在 winapi 中是正式允许的,窗口的所有者可以是另一个线程拥有的窗口。但这是 Microsoft 在将代码添加到 .NET 2.0 中以检测线程错误时并未实现的规则。解决该代码需要一个 IWin32Window 作为消息框所有者,它不是一个控件。

向您的项目添加一个新类并粘贴此代码:

using System;
using System.Threading;
using System.Windows.Forms;

public class NonModalMessageBox : IWin32Window {
public NonModalMessageBox(Form owner, Action<IWin32Window> display) {
this.handle = owner.Handle;
var t = new Thread(new ThreadStart(() => display(this)));
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public IntPtr Handle {
get { return handle; }
}
private IntPtr handle;
}

然后像这样使用它:

        new NonModalMessageBox(this, (owner) => {
MessageBox.Show(owner, "Testing", "Non-modal");
});

其中 this 显示消息框时应禁用的 Form 对象。我几乎无法让您对这个 hack 感觉更好,如果 FUD 过于强烈,那么您确实需要用您自己的 Form 类重新实现 MessageBox,这样您就可以使用 Show() 而不是 ShowDialog()。已经完成了。

关于c# - MessageBox模态到单一形式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30478666/

54 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com