以编程方式强制关闭 MessageBox

发布于 2024-12-12 12:26:18 字数 322 浏览 0 评论 0原文

让我给你介绍一下背景。

我们有一个应用程序(中型)在不同的地方(数百个)使用 MessageBox.Show (....)。

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

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

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

Let me give you the background.

We have an Application(medium sized) that is using MessageBox.Show (....) at various places (in hundreds).

These message boxes are part of workflow and being used for informing,warning or taking input from an user. Application is supposed to automatically log off after certain time if there is no activity. We have a requirement that while logging out the application, just to clean the session data , to clear views and to hide itself so that in next launch, it won't have to execute the startup process which is costly in terms of time.

Everything is working fine but in a scenario when there is some message box on the screen and user left the machine without responding to message box and then due to no activity to make the application to log out. Problem is Message box won't disappear.

How I can close the opened messagebox, if any, while hiding the application?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

小鸟爱天空丶 2024-12-19 12:26:18

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

    /// <summary>
    /// Attempt to close modal windows if there are any.
    /// </summary>
    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 应用程序,当您按下某个按钮时会弹出 MessageBox1,您仍然可以使用 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,这只是一个示例。

Here is a piece of code based on UIAutomation (a cool but still not very used API) that attempts to close all modal windows (including the one opened with MessageBox) of the current process:

    /// <summary>
    /// Attempt to close modal windows if there are any.
    /// </summary>
    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();
                    }
                }
            }
        }
    }

For example, if you have a WinForms application that pops up a MessageBox when you press some button1, you will still be able to close the app using Windows "Close Window" menu (right click in the task bar):

    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);
    }

You could use CloseModalWindows somewhere else in your code of course, this is just a sample.

忘你却要生生世世 2024-12-19 12:26:18

链接 MSDN 论坛上展示了如何使用 FindWindow 并发送一个消息来关闭消息框WM_CLOSE 消息。虽然这个问题是针对.NET/WindowsCE提出的,但它可能会解决你的问题,值得一看

This link on MSDN forums shows how to close a message box by using FindWindow and sending a WM_CLOSE message. Although the question was asked for .NET/WindowsCE, it might solve your problem, its worth a look

萌︼了一个春 2024-12-19 12:26:18

MessageBox”

请参阅DmitryG 帖子“几秒钟后关闭 超时后的 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);

Refer to DmitryG post in "Close a MessageBox after several seconds"

Auto-Close MessageBox after timeout reach

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);
    }

and Call it via

AutoClosingMessageBox.Show("Content", "Title", TimeOut);
氛圍 2024-12-19 12:26:18

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

我认为您有三个选择

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

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

  3. 摆脱消息框干扰工作流程。这可能是最好的解决方案,因为从它以编程方式关闭消息框的声音来看,这将导致工作流程继续/更改,甚至可能导致另一个消息框显示,这可能是不合需要的。但显然解决根本问题可能是最好的,但并不总是最简单的。

1 和 2 需要从单独的线程完成,因此您需要考虑其含义,因为显示消息框将被阻塞。

First a Question: If messages boxes are used as part of workflow, won't programatically closing message box cause the flow to change/continue?

I think you have three options

  1. Create your own version of the messagebox class that opens a dialog window that looks like a messagebox with added functionality so it closed automatically after a period of time.

  2. Implement something like this in c# to close message boxes programtically.
    http://www.codeproject.com/KB/dialog/AutoCloseMessageBox.aspx

  3. Get rid of the message boxes from interupting the workflow. This is probably the best solution as from the sound of it closing a message box programatically will cause workflow to continue/change, and perhaps even cause another messagebox to show which may not be desirable. But obviously fixing the root problem might be best, but isn't always the easiest.

1 and 2 would need to be done from a separate thread, so you will need to think about the implications of that as showing the messagebox will be blocking.

偏闹i 2024-12-19 12:26:18

这是我使用 SendKeys 的示例 - 经过测试并正常工作:

假设我们在表单中有后台工作者和按钮。单击按钮后 - 启动工作程序并显示消息框。在工人 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
}

Heres my example with SendKeys - tested and working:

lets say we have backgroundworker and button in form. After button was click - start worker and show message box. In workers DoWork event sleep for 5s and then send enter key - messsage box closed.

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
}
青芜 2024-12-19 12:26:18

这个主题已经在其他 SO 问题中得到了丰富的介绍,但由于这个特定的问题有几个关于使用 UI 自动化/窗口查找技术(我不是特别喜欢)的答案以及关于在不提供代码的情况下创建自己的对话框的一般建议,我决定发布我的自己的解决方案。可以创建一个可实例化的 MessageBox 类,如下所示:

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace Common
{
    // Loosely based on: https://www.codeproject.com/Articles/17253/A-Custom-Message-Box
    class MsgBox : Form
    {
        private Panel _plHeader = new Panel();
        private Panel _plFooter = new Panel();
        private Panel _plIcon = new Panel();
        private PictureBox _picIcon = new PictureBox();
        private FlowLayoutPanel _flpButtons = new FlowLayoutPanel();
        private Label _lblMessage;

        private MsgBox()
        {
            FormBorderStyle = FormBorderStyle.FixedDialog;
            BackColor = Color.White;
            StartPosition = FormStartPosition.CenterScreen;
            MinimizeBox = false;
            MaximizeBox = false;
            ShowIcon = false;
            Width = 400;

            _lblMessage = new Label();
            _lblMessage.Font = new Font("Segoe UI", 10);
            _lblMessage.Dock = DockStyle.Fill;
            _lblMessage.TextAlign = ContentAlignment.MiddleLeft;

            _flpButtons.FlowDirection = FlowDirection.RightToLeft;
            _flpButtons.Dock = DockStyle.Fill;

            //_plHeader.FlowDirection = FlowDirection.TopDown;
            _plHeader.Dock = DockStyle.Fill;
            _plHeader.Padding = new Padding(20);
            _plHeader.Controls.Add(_lblMessage);

            _plFooter.Dock = DockStyle.Bottom;
            _plFooter.BackColor = Color.FromArgb(240, 240, 240);
            _plFooter.Padding = new Padding(10);
            _plFooter.Height = 60;
            _plFooter.Controls.Add(_flpButtons);

            _picIcon.Location = new Point(30, 50);

            _plIcon.Dock = DockStyle.Left;
            _plIcon.Padding = new Padding(20);
            _plIcon.Width = 70;
            _plIcon.Controls.Add(_picIcon);

            Controls.Add(_plHeader);
            Controls.Add(_plIcon);
            Controls.Add(_plFooter);
        }

        public static DialogResult Show(IWin32Window owner, string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
        {
            var msgBox = Create(message, title, buttons, icon);
            return msgBox.ShowDialog(owner);
        }

        public static DialogResult Show(string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
        {
            var msgBox = Create(message, title, buttons, icon);
            return msgBox.ShowDialog();
        }

        public static MsgBox Create(string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
        {
            var msgBox = new MsgBox();
            msgBox.Init(message, title, buttons, icon);
            return msgBox;
        }

        void Init(string message, string title, MessageBoxButtons? buttons, MessageBoxIcon icon)
        {
            _lblMessage.Text = message;
            Text = title;
            InitButtons(buttons);
            InitIcon(icon);
            Size = MessageSize(message);
        }

        void InitButtons(MessageBoxButtons? buttons)
        {
            if (!buttons.HasValue)
                return;

            switch (buttons)
            {
                case MessageBoxButtons.AbortRetryIgnore:
                    AddButton("Ignore");
                    AddButton("Retry");
                    AddButton("Abort");
                    break;

                case MessageBoxButtons.OK:
                    AddButton("OK");
                    break;

                case MessageBoxButtons.OKCancel:
                    AddButton("Cancel");
                    AddButton("OK");
                    break;

                case MessageBoxButtons.RetryCancel:
                    AddButton("Cancel");
                    AddButton("Retry");
                    break;

                case MessageBoxButtons.YesNo:
                    AddButton("No");
                    AddButton("Yes");
                    break;

                case MessageBoxButtons.YesNoCancel:
                    AddButton("Cancel");
                    AddButton("No");
                    AddButton("Yes");
                    break;
            }
        }

        void InitIcon(MessageBoxIcon icon)
        {
            switch (icon)
            {
                case MessageBoxIcon.None:
                    _picIcon.Hide();
                    break;
                case MessageBoxIcon.Exclamation:
                    _picIcon.Image = SystemIcons.Exclamation.ToBitmap();
                    break;

                case MessageBoxIcon.Error:
                    _picIcon.Image = SystemIcons.Error.ToBitmap();
                    break;

                case MessageBoxIcon.Information:
                    _picIcon.Image = SystemIcons.Information.ToBitmap();
                    break;

                case MessageBoxIcon.Question:
                    _picIcon.Image = SystemIcons.Question.ToBitmap();
                    break;
            }

            _picIcon.Width = _picIcon.Image.Width;
            _picIcon.Height = _picIcon.Image.Height;
        }

        private void ButtonClick(object sender, EventArgs e)
        {
            Button btn = (Button)sender;

            switch (btn.Text)
            {
                case "Abort":
                    DialogResult = DialogResult.Abort;
                    break;

                case "Retry":
                    DialogResult = DialogResult.Retry;
                    break;

                case "Ignore":
                    DialogResult = DialogResult.Ignore;
                    break;

                case "OK":
                    DialogResult = DialogResult.OK;
                    break;

                case "Cancel":
                    DialogResult = DialogResult.Cancel;
                    break;

                case "Yes":
                    DialogResult = DialogResult.Yes;
                    break;

                case "No":
                    DialogResult = DialogResult.No;
                    break;
            }

            Close();
        }

        private static Size MessageSize(string message)
        {
            int width=350;
            int height = 230;

            SizeF size = TextRenderer.MeasureText(message, new Font("Segoe UI", 10));

            if (message.Length < 150)
            {
                if ((int)size.Width > 350)
                {
                    width = (int)size.Width;
                }
            }
            else
            {
                string[] groups = (from Match m in Regex.Matches(message, ".{1,180}") select m.Value).ToArray();
                int lines = groups.Length+1;
                width = 700;
                height += (int)(size.Height+10) * lines;
            }
            return new Size(width, height);
        }

        private void AddButton(string caption)
        {
            var btn = new Button();
            btn.Text = caption;
            btn.Font = new Font("Segoe UI", 8);
            btn.BackColor = Color.FromArgb(225, 225, 225);
            btn.Padding = new Padding(3);
            btn.Height = 30;
            btn.Click += ButtonClick;
            _flpButtons.Controls.Add(btn);
        }
    }
}

然后可以将对话框的引用保留在类作用域中,显示对话框并获取结果,或者只是在应用程序退出中将其关闭事件处理程序。

MsgBox _msgBox;

void eventHandler1(object sender, EventArgs e)
{
    _msgBox = MsgBox.Create("Do you want to continue", "Inquiry", MessageBoxButtons.YesNo);
    var result = _msgBox.ShowDialog();
    // do something with result
}

void applicationExitHandler(object sender, EventArgs e)
{
    if (_msgBox != null)
        _msgBox.Close();
}

This topic has been abundantly covered in other SO questions but since this particular one has several answers about using UI automation/window lookup techniques (which I don't particularly like) and generic suggestions about creating own dialog without provided code, I decided post my own solution. One can create an instantiable MessageBox like class as it follows:

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace Common
{
    // Loosely based on: https://www.codeproject.com/Articles/17253/A-Custom-Message-Box
    class MsgBox : Form
    {
        private Panel _plHeader = new Panel();
        private Panel _plFooter = new Panel();
        private Panel _plIcon = new Panel();
        private PictureBox _picIcon = new PictureBox();
        private FlowLayoutPanel _flpButtons = new FlowLayoutPanel();
        private Label _lblMessage;

        private MsgBox()
        {
            FormBorderStyle = FormBorderStyle.FixedDialog;
            BackColor = Color.White;
            StartPosition = FormStartPosition.CenterScreen;
            MinimizeBox = false;
            MaximizeBox = false;
            ShowIcon = false;
            Width = 400;

            _lblMessage = new Label();
            _lblMessage.Font = new Font("Segoe UI", 10);
            _lblMessage.Dock = DockStyle.Fill;
            _lblMessage.TextAlign = ContentAlignment.MiddleLeft;

            _flpButtons.FlowDirection = FlowDirection.RightToLeft;
            _flpButtons.Dock = DockStyle.Fill;

            //_plHeader.FlowDirection = FlowDirection.TopDown;
            _plHeader.Dock = DockStyle.Fill;
            _plHeader.Padding = new Padding(20);
            _plHeader.Controls.Add(_lblMessage);

            _plFooter.Dock = DockStyle.Bottom;
            _plFooter.BackColor = Color.FromArgb(240, 240, 240);
            _plFooter.Padding = new Padding(10);
            _plFooter.Height = 60;
            _plFooter.Controls.Add(_flpButtons);

            _picIcon.Location = new Point(30, 50);

            _plIcon.Dock = DockStyle.Left;
            _plIcon.Padding = new Padding(20);
            _plIcon.Width = 70;
            _plIcon.Controls.Add(_picIcon);

            Controls.Add(_plHeader);
            Controls.Add(_plIcon);
            Controls.Add(_plFooter);
        }

        public static DialogResult Show(IWin32Window owner, string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
        {
            var msgBox = Create(message, title, buttons, icon);
            return msgBox.ShowDialog(owner);
        }

        public static DialogResult Show(string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
        {
            var msgBox = Create(message, title, buttons, icon);
            return msgBox.ShowDialog();
        }

        public static MsgBox Create(string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
        {
            var msgBox = new MsgBox();
            msgBox.Init(message, title, buttons, icon);
            return msgBox;
        }

        void Init(string message, string title, MessageBoxButtons? buttons, MessageBoxIcon icon)
        {
            _lblMessage.Text = message;
            Text = title;
            InitButtons(buttons);
            InitIcon(icon);
            Size = MessageSize(message);
        }

        void InitButtons(MessageBoxButtons? buttons)
        {
            if (!buttons.HasValue)
                return;

            switch (buttons)
            {
                case MessageBoxButtons.AbortRetryIgnore:
                    AddButton("Ignore");
                    AddButton("Retry");
                    AddButton("Abort");
                    break;

                case MessageBoxButtons.OK:
                    AddButton("OK");
                    break;

                case MessageBoxButtons.OKCancel:
                    AddButton("Cancel");
                    AddButton("OK");
                    break;

                case MessageBoxButtons.RetryCancel:
                    AddButton("Cancel");
                    AddButton("Retry");
                    break;

                case MessageBoxButtons.YesNo:
                    AddButton("No");
                    AddButton("Yes");
                    break;

                case MessageBoxButtons.YesNoCancel:
                    AddButton("Cancel");
                    AddButton("No");
                    AddButton("Yes");
                    break;
            }
        }

        void InitIcon(MessageBoxIcon icon)
        {
            switch (icon)
            {
                case MessageBoxIcon.None:
                    _picIcon.Hide();
                    break;
                case MessageBoxIcon.Exclamation:
                    _picIcon.Image = SystemIcons.Exclamation.ToBitmap();
                    break;

                case MessageBoxIcon.Error:
                    _picIcon.Image = SystemIcons.Error.ToBitmap();
                    break;

                case MessageBoxIcon.Information:
                    _picIcon.Image = SystemIcons.Information.ToBitmap();
                    break;

                case MessageBoxIcon.Question:
                    _picIcon.Image = SystemIcons.Question.ToBitmap();
                    break;
            }

            _picIcon.Width = _picIcon.Image.Width;
            _picIcon.Height = _picIcon.Image.Height;
        }

        private void ButtonClick(object sender, EventArgs e)
        {
            Button btn = (Button)sender;

            switch (btn.Text)
            {
                case "Abort":
                    DialogResult = DialogResult.Abort;
                    break;

                case "Retry":
                    DialogResult = DialogResult.Retry;
                    break;

                case "Ignore":
                    DialogResult = DialogResult.Ignore;
                    break;

                case "OK":
                    DialogResult = DialogResult.OK;
                    break;

                case "Cancel":
                    DialogResult = DialogResult.Cancel;
                    break;

                case "Yes":
                    DialogResult = DialogResult.Yes;
                    break;

                case "No":
                    DialogResult = DialogResult.No;
                    break;
            }

            Close();
        }

        private static Size MessageSize(string message)
        {
            int width=350;
            int height = 230;

            SizeF size = TextRenderer.MeasureText(message, new Font("Segoe UI", 10));

            if (message.Length < 150)
            {
                if ((int)size.Width > 350)
                {
                    width = (int)size.Width;
                }
            }
            else
            {
                string[] groups = (from Match m in Regex.Matches(message, ".{1,180}") select m.Value).ToArray();
                int lines = groups.Length+1;
                width = 700;
                height += (int)(size.Height+10) * lines;
            }
            return new Size(width, height);
        }

        private void AddButton(string caption)
        {
            var btn = new Button();
            btn.Text = caption;
            btn.Font = new Font("Segoe UI", 8);
            btn.BackColor = Color.FromArgb(225, 225, 225);
            btn.Padding = new Padding(3);
            btn.Height = 30;
            btn.Click += ButtonClick;
            _flpButtons.Controls.Add(btn);
        }
    }
}

One can then just keep the reference of the dialog in a class scope, show the dialog and get the result, or just close it in an application exit event handler.

MsgBox _msgBox;

void eventHandler1(object sender, EventArgs e)
{
    _msgBox = MsgBox.Create("Do you want to continue", "Inquiry", MessageBoxButtons.YesNo);
    var result = _msgBox.ShowDialog();
    // do something with result
}

void applicationExitHandler(object sender, EventArgs e)
{
    if (_msgBox != null)
        _msgBox.Close();
}
我的影子我的梦 2024-12-19 12:26:18

我认为最干净的方法是实现您自己的消息框表单,例如

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 消息。

I think the cleanest way would be to implement you own message box form like

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();
  }

  // ...
}

In some of my larger projects, I found this approach useful also for other purposes (such as automatic logging of error messages etc.)

The second idea I have would be to use GetTopWindow() (or maybe some other WIN32 function) to get the current top-level window of your application and send a WM_CLOSE message to it.

指尖凝香 2024-12-19 12:26:18

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

此处就是一个很好的例子。

Taking as an assumption that you can edit the code that's calling the
MessageBox.Show() method, I would recommend not use
MessageBox. Instead, just use your own custom form, calling ShowDialog()
on it to do basically the same thing as the MessageBox class. Then, you
have the instance of the form itself, and you can call Close() on that
instance to close it.

A good example is here.

故事还在继续 2024-12-19 12:26:18

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

使用 MessageBox.Show(this,"message") 从存根表单打开 MessageBox。

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

  1. 保留表单处理程序并通过以下方式关闭它:

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

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

由于Form是MessageBox的所有者,关闭它就会关闭MessageBox。

I used .net 2 and two approaches with the same trick.

Open the MessageBox from stub-Form with MessageBox.Show(this,"message")

When the form is not visible or doesn't has really UI.

  1. Keep the form handler and close it with:

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

    or

  2. holding the form as class parameter and using FormX.Close().

Since the Form is the owner of the MessageBox, Closing it will close the MessageBox.

叹倦 2024-12-19 12:26:18

最简单的解决方案是创建一个将在timer_tick上关闭的窗体,

private int interval = 0;
private string message = "";

public msgBox(string msg = "", int i = 0)
{
    InitializeComponent();
    interval = i;
    message = msg;
}

private void MsgBox_Load(object sender, EventArgs e)
{
    if (interval > 0)
        timer1.Interval = interval;

    lblMessage.Text = message;
    lblMessage.Width = panel1.Width - 20;
    lblMessage.Left = 10;
}

private void Timer1_Tick(object sender, EventArgs e)
{
    this.Close();
}

private void Panel1_Paint(object sender, PaintEventArgs e)
{
    ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Solid);
}

以在主窗体中使用

   private void showMessage(string msg, int interval = 0)
    {
        msgBox mb = new msgBox(msg, interval);
        mb.ShowDialog(this);
    }

调用它

  showMessage("File saved");

The easiest solution is to create a form that will close on timer_tick

private int interval = 0;
private string message = "";

public msgBox(string msg = "", int i = 0)
{
    InitializeComponent();
    interval = i;
    message = msg;
}

private void MsgBox_Load(object sender, EventArgs e)
{
    if (interval > 0)
        timer1.Interval = interval;

    lblMessage.Text = message;
    lblMessage.Width = panel1.Width - 20;
    lblMessage.Left = 10;
}

private void Timer1_Tick(object sender, EventArgs e)
{
    this.Close();
}

private void Panel1_Paint(object sender, PaintEventArgs e)
{
    ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Solid);
}

Method to use in main form

   private void showMessage(string msg, int interval = 0)
    {
        msgBox mb = new msgBox(msg, interval);
        mb.ShowDialog(this);
    }

Call it

  showMessage("File saved");
遥远的绿洲 2024-12-19 12:26:18

我想出了一个简单的解决方案,不需要实现任何额外的类或方法。

关键思想:您将一个不可见的表单作为所有者传递给消息框。您可以随时使用 Form.Close() 关闭该所有者表单,这将关闭您的 MessageBox。

// create an invisible Form to be the Owner of the MessageBox
Form myMessageBox = new Form() {
   Owner = MainWindow, // in case you have a main application window
   Size = new System.Drawing.Size(0, 0)
};

MainWindow.BeginInvoke(
    new Action(() =>
    {
        MessageBox.Show(
            myMessageBox, //this is key, here you pass the myMessageBox as owner of the Messagebox
            "The Message",
            "The Window Title",
            MessageBoxButtons.OK,
            MessageBoxIcon.Information,
            MessageBoxDefaultButton.Button1
        );
    }
));


if(messageBoxShallBeClosed)
{
    // whenever or whereever you want to close the MessageBox execute the following
    MainWindow.Invoke(
        new Action(() =>
        {
            myMessageBox.Close(); // this closes the MessageBox, since it is the owner of it
        }
    ));
}

I figured out a simple Solution, that does not require implementing any additional classes or methods.

Key idea: You pass an invisible form as owner to the message box. You can close that owner form whenever you want with Form.Close() which will close your MessageBox.

// create an invisible Form to be the Owner of the MessageBox
Form myMessageBox = new Form() {
   Owner = MainWindow, // in case you have a main application window
   Size = new System.Drawing.Size(0, 0)
};

MainWindow.BeginInvoke(
    new Action(() =>
    {
        MessageBox.Show(
            myMessageBox, //this is key, here you pass the myMessageBox as owner of the Messagebox
            "The Message",
            "The Window Title",
            MessageBoxButtons.OK,
            MessageBoxIcon.Information,
            MessageBoxDefaultButton.Button1
        );
    }
));


if(messageBoxShallBeClosed)
{
    // whenever or whereever you want to close the MessageBox execute the following
    MainWindow.Invoke(
        new Action(() =>
        {
            myMessageBox.Close(); // this closes the MessageBox, since it is the owner of it
        }
    ));
}

沧桑㈠ 2024-12-19 12:26:18

为此创建您自己的控件并实现您想要的行为。作为一个选项,可能有一个计时器来关闭此消息框。

Create your own control for this and implement behavior you like to have there. As an option there may be a timer to close this MessageBox.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文