强制以编程方式关闭MessageBox

我来给你一个背景。

我们有一个应用程序(中等大小)在各个地方(数百个)使用MessageBox.Show(….)。

这些消息框是工作流程的一部分,用于通知,警告或从用户获取输入。 如果没有活动,应用程序应该在一定时间后自动注销。 我们要求在注销应用程序时,只需清理会话数据,清除视图并隐藏自身,以便在下次启动时,它不必执行启动过程,这在时间上是昂贵的。

一切正常,但是在屏幕上有一些消息框并且用户离开机器而没有响应消息框然后由于没有活动使应用程序退出的情况下。 问题是消息框不会消失。

如何在隐藏应用程序时关闭打开的消息框(如果有的话)?

谢谢。

这是一段基于UIAutomation (一个很酷但仍未使用的API)的代码,它试图关闭当前进程的所有模态窗口(包括用MessageBox打开的窗口):

  ///  /// Attempt to close modal windows if there are any. ///  public static void CloseModalWindows() { // get the main window AutomationElement root = AutomationElement.FromHandle(Process.GetCurrentProcess().MainWindowHandle); if (root == null) return; // it should implement the Window pattern object pattern; if (!root.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) return; WindowPattern window = (WindowPattern)pattern; if (window.Current.WindowInteractionState != WindowInteractionState.ReadyForUserInteraction) { // get sub windows foreach (AutomationElement element in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window))) { // hmmm... is it really a window? if (element.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) { // if it's ready, try to close it WindowPattern childWindow = (WindowPattern)pattern; if (childWindow.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction) { childWindow.Close(); } } } } } 

例如,如果你有一个WinForms应用程序,当你按下某个按钮1时弹出一个MessageBox,你仍然可以使用Windows“关闭窗口”菜单关闭应用程序(右键单击任务栏):

  private void button1_Click(object sender, EventArgs e) { MessageBox.Show("Don't click me. I want to be closed automatically!"); } protected override void WndProc(ref System.Windows.Forms.Message m) { const int WM_SYSCOMMAND = 0x0112; const int SC_CLOSE = 0xF060; if (m.Msg == WM_SYSCOMMAND) // this is sent even if a modal MessageBox is shown { if ((int)m.WParam == SC_CLOSE) { CloseModalWindows(); Close(); } } base.WndProc(ref m); } 

您可以在代码中的其他位置使用CloseModalWindows,这只是一个示例。

MSDN论坛上的此链接显示如何使用FindWindow并发送WM_CLOSE消息来关闭消息框。 虽然问题是.NET / WindowsCE,但它可能会解决您的问题,值得一看

首先问题:如果消息框用作工作流的一部分,不会以编程方式关闭消息框导致流程更改/继续?

我想你有三个选择

  1. 创建自己的messagebox类版本,打开一个对话框窗口,该窗口看起来像一个带有附加function的消息框,因此在一段时间后会自动关闭。

  2. 在c#中实现类似的function,以编程方式关闭消息框。 http://www.codeproject.com/KB/dialog/AutoCloseMessageBox.aspx

  3. 从中断工作流程中删除消息框。 这可能是最好的解决方案,因为它以编程方式关闭消息框的声音将导致工作流程继续/更改,甚至可能导致另一个消息框显示哪些可能不合适。 但显然解决根本问题可能是最好的,但并不总是最容易的。

1和2需要从一个单独的线程完成,所以你需要考虑它的含义,因为显示消息框将被阻止。

以下是我使用SendKeys的例子 – 测试和工作:

让我们说我们有背景工作和按钮的forms。 单击按钮后 – 启动工作人员并显示消息框。 在工人DoWork事件中睡5秒然后发送回车键 – 消息框关闭。

 private void button1_Click(object sender, EventArgs e) { backgroundWorker1.RunWorkerAsync(); MessageBox.Show("Close this message!"); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Thread.Sleep(5000); SendKeys.SendWait("{Enter}");//or Esc } 

假设您可以编辑调用MessageBox.Show()方法的代码,我建议不要使用MessageBox。 相反,只需使用自己的自定义表单,在其上调用ShowDialog()就可以完成与MessageBox类基本相同的操作。 然后,您拥有表单本身的实例,并且可以在该实例上调用Close()来关闭它。

这是一个很好的例子。

我认为最干净的方法是实现你自己的消息框forms

 class MyMessageBox : Form { private MyMessageBox currentForm; // The currently active message box public static Show(....) { // same as MessageBox.Show // ... } public static Show(...) { // define additional overloads } public static CloseCurrent() { if (currentForm != null) currentForm.Close(); } // ... } 

在我的一些大型项目中,我发现这种方法也可用于其他目的(例如自动记录错误消息等)

我的第二个想法是使用GetTopWindow() (或者其他一些WIN32函数)来获取应用程序的当前顶级窗口并向其发送WM_CLOSE消息。

我使用.net 2和两种方法使用相同的技巧。

使用MessageBox.Show从此存根窗体打开MessageBox.Show(this,"message")

当表单不可见或没有真正的UI时。

  1. 保留表单处理程序并将其关闭:

     static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 

    要么

  2. 将表单保存为类参数并使用FormX.Close()

由于Form是MessageBox的所有者,因此关闭它将关闭MessageBox。

请参阅“几秒钟后关闭一个MessageBox”中的DmitryGpost

超时到达后自动关闭MessageBox

 using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; public class AutoClosingMessageBox { System.Threading.Timer _timeoutTimer; string _caption; AutoClosingMessageBox(string text, string caption, int timeout) { _caption = caption; _timeoutTimer = new System.Threading.Timer(OnTimerElapsed, null, timeout, System.Threading.Timeout.Infinite); MessageBox.Show(text, caption); } public static void Show(string text, string caption, int timeout) { new AutoClosingMessageBox(text, caption, timeout); } void OnTimerElapsed(object state) { IntPtr mbWnd = FindWindow(null, _caption); if (mbWnd != IntPtr.Zero) SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); _timeoutTimer.Dispose(); } const int WM_CLOSE = 0x0010; [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); } 

并通过它来调用它

 AutoClosingMessageBox.Show("Content", "Title", TimeOut); 

为此创建自己的控件并实现您希望拥有的行为。 作为选项,可能有一个计时器来关闭此MessageBox。

Interesting Posts