无需用户输入,程序化拆除MessageBox

7
我经常使用MessageBox弹出警示消息,提示用户。我的特定应用程序可以被设置为远程运行,所以有时候用户面对着计算机,而有时候用户可能长达几小时甚至几天不在计算机前。有时我使用MessageBox弹出一个警示消息,但是一段时间后这个警示就不再具有参考价值了。例如,我弹出一个警示消息说由于某些条件未满足,任务无法完成。几分钟后,这个条件得到满足,任务开始执行。那个MessageBox就不再相关了。
我希望能够在这些情况下通过编程的方式关闭MessageBox。这是否可能?目前我使用一个线程创建我的MessageBox对象:
new Thread(() => MessageBox.Show("Some text", "Some caption")).Start();

我这样做是为了让应用程序在后台继续运行,而不会被MessageBox所阻止。有什么建议吗?


1
也许你需要一些自定义的消息框。 - King King
我倾向于这样做。只是好奇是否有一种方法可以使用现有的 MessageBox 来实现这一点。我讨厌重复造轮子。 - Michael Mankus
实际上,这并不是所谓的“重复造轮子”,如果你也想要一些自定义外观,那么这是唯一的方法,而且也不需要太多工作量。我认为没有办法从标准的“MessageBox”开始,虽然我从未尝试过,但你也可以使用一些“Win32”函数来创建一些非模态 MessageBox。 - King King
1
顺便说一句,我猜你的消息框只有一个“确定”按钮,所以与用户的交互并不是必要的,你可以尝试使用某种“通知窗口”代替。 - King King
6个回答

6
这对我有用。
public partial class Form1 : Form
{
    [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
    static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

    [DllImport("user32.Dll")]
    static extern int PostMessage(IntPtr hWnd, UInt32 msg, int wParam, int lParam);

    const UInt32 WM_CLOSE = 0x0010;

    Thread thread;

    public Form1()
    {
        InitializeComponent();

        thread = new Thread(ShowMessageBox);
        thread.Start();
    }

    void CloseMessageBox()
    {
        IntPtr hWnd = FindWindowByCaption(IntPtr.Zero, "Caption");
        if (hWnd != IntPtr.Zero)
            PostMessage(hWnd, WM_CLOSE, 0, 0);

        if (thread.IsAlive)
            thread.Abort();
    }

    static void ShowMessageBox()
    {
        MessageBox.Show("Message", "Caption");
    }
}

现在你可以使用CloseMessageBox()来关闭消息框。但是请注意,在CloseMessageBox()ShowMessageBox()中标题必须相同!或许可以通过全局变量实现,但这取决于你。

在我的测试中(Windows 7),使用MessageBox.Show(this, "Abort?", AlertCaption, MessageBoxButtons.OKCancel)可以工作,但是使用MessageBox.Show(this, "Abort?", AlertCaption, MessageBoxButtons.YesNo)却无效。后者没有任何反应(警告仍然打开)。有任何想法吗? - Alex
我注意到在YesNo对话框中按Esc键无效(因此WM_CLOSE消息没有任何作用)。您有什么想法在发送哪个窗口时可以使其响应好像按下了“否”? - Alex
嗯,看起来非常复杂,有人提到它在非英语Windows上无法工作。我想我需要重构我的用户界面,这样它就可以使用“确定/取消”而不是“是/否”。 - Alex
Andy,有没有C++的方法可以将MessageBox移动到指定位置? - Yoda

2
您可以使用以下类轻松创建 MessageBox:
```

您可以使用以下类轻松创建 MessageBox:

```
using System;
using System.Runtime.InteropServices;

public class MsgBox
{
    [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    static extern bool EndDialog(IntPtr hDlg, int nResult);

    [DllImport("user32.dll")]
    static extern int MessageBoxTimeout(IntPtr hwnd, string txt, string caption,
        int wtype, int wlange, int dwtimeout);

    const int WM_CLOSE = 0x10;

    public static int Show(string text, string caption, int milliseconds, MsgBoxStyle style)
    {
        return MessageBoxTimeout(IntPtr.Zero, text, caption, (int)style, 0, milliseconds);
    }

    public static int Show(string text, string caption, int milliseconds, int style)
    {
        return MessageBoxTimeout(IntPtr.Zero, text, caption, style, 0, milliseconds);
    }
    public static int Show(string text, string caption, int milliseconds)
    {
        return MessageBoxTimeout(IntPtr.Zero, text, caption, 0, 0, milliseconds);
    }
}

public enum MsgBoxStyle
{
    OK = 0, OKCancel = 1, AbortRetryIgnore = 2, YesNoCancel = 3, YesNo = 4,
    RetryCancel = 5, CancelRetryContinue = 6,

    RedCritical_OK = 16, RedCritical_OKCancel = 17, RedCritical_AbortRetryIgnore = 18,
    RedCritical_YesNoCancel = 19, RedCritical_YesNo = 20,
    RedCritical_RetryCancel = 21, RedCritical_CancelRetryContinue = 22,

    BlueQuestion_OK = 32, BlueQuestion_OKCancel = 33, BlueQuestion_AbortRetryIgnore = 34,
    BlueQuestion_YesNoCancel = 35, BlueQuestion_YesNo = 36,
    BlueQuestion_RetryCancel = 37, BlueQuestion_CancelRetryContinue = 38,

    YellowAlert_OK = 48, YellowAlert_OKCancel = 49, YellowAlert_AbortRetryIgnore = 50,
    YellowAlert_YesNoCancel = 51, YellowAlert_YesNo = 52,
    YellowAlert_RetryCancel = 53, YellowAlert_CancelRetryContinue = 54,

    BlueInfo_OK = 64, BlueInfo_OKCancel = 65, BlueInfo_AbortRetryIgnore = 66,
    BlueInfo_YesNoCancel = 67, BlueInfo_YesNo = 68,
    BlueInfo_RetryCancel = 69, BlueInfo_CancelRetryContinue = 70,
}

使用方法:

MsgBox.Show("this is content", "this is caption", 3000);

2
为什么不制作一个自定义消息框呢?您可以让它在固定的时间内显示,或者直到您的应用程序通过代码关闭它。
创建一个自定义消息框实例(Form类子类),并将其保存为变量(例如MyMessageBox),然后使用MyMessageBox.Show();显示它。当您想要关闭它时,请调用MyMessageBox.Close(); 如果您在另一个线程中打开它时无法关闭它,请尝试调用MyMessageBox.Invoke(new Action(() => {MyMessageBox.Close();}));。这将在与MyMessageBox创建的同一线程上运行命令MyMessageBox.Close();,以避免出现问题。

0

为了知道何时启动msgbox或不启动,对您的条件进行例外处理。例如:

if (criteria)
{
    new Thread(() => MessageBox.Show("Some text", "Some caption")).Start();
}
else
{
    //do nothing
}

3
他说目前可能不符合条件,但以后可能会符合,所以消息将不相关但仍将保留。问题是如何“删除”消息框,而不是如何“开始”它。 - Tafari
如果没有任何人在这里点踩,我怀疑这个答案至少会收到两个踩。 - King King

0
如果您使用DevExpress,那么您可以执行以下操作: 应用程序具有属性OpenForms,其中包含应用程序的所有打开窗体。您仍然无法找到特定的消息框,但是您可以关闭所有XtraMessageBox。或者,在关闭之前检查某个任务/线程中运行的MessageBox。

0

你可能想考虑为你的消息使用一个LogFile,以及在你的主窗体中嵌入一个richtextbox(或多行文本框),然后你可以在那里发布你的消息(每行1个,带有时间戳)。至于你的消息框问题,我不确定是否有一种(好的)方法来编程关闭它们。(中止线程不起作用)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接