【问题标题】:Open multiple instances of MessageBox and automatically close after several seconds打开多个 MessageBox 实例并在几秒钟后自动关闭
【发布时间】:2014-02-04 15:05:51
【问题描述】:

我正在 Visual Studio 2012 下用 C# 编写 Windows 窗体,我想打开多个 MessageBox 实例并在几秒钟后自动关闭它们

我在这里找到(并赞成)这个答案:SO: Close a MessageBox after several seconds

但是,如果我一次只打开 1(一个)MessageBox,则此方法有效,因为它使用函数 FindWindow,并且我的 MessageBox 的多个实例应具有所有相同的窗口标题(标题)。

[可选]另外,我想给用户一个倒计时,比如这个对话框将在 5 秒后关闭这个 [.. .] 4 秒内这个 [...] 3 秒内,...,这个 [...] 1 秒内 然后最后关闭消息框。

有没有办法唯一地引用我的多个 MessageBox 并在一段时间后(比如 5秒)?

【问题讨论】:

  • 您确定消息框是正确的解决方案吗?听起来您正在尝试重新实现通知。
  • 嗨@Damien_The_Unbeliever,我已经考虑并研究了通知,但就我而言,我真的需要消息框......(:

标签: c# winforms timer messagebox auto-close


【解决方案1】:

我建议不要为此任务使用 MessageBox。相反,制作您自己的自定义表单。使其具有您想要的大小、形状和外观。然后,在其代码隐藏文件中,您可以创建一个计时器,该计时器是该窗口本身独有的。这样,您可以根据需要生成任意数量的它们,它们将管理自己的计时器并自行关闭,而您无需执行任何操作,例如查找窗口。可以使 Form 看起来非常像 MessageBox。由于您可以调用 ShowDialog,因此您也可以使它们的行为与 MessageBox 相似(尽管这会适得其反,因为您一次只能与一个对话框交互)。

【讨论】:

  • 嗨@Curtis Rutland 感谢您的想法和使用自定义表单模拟 MessageBox 的想法。我一定会进一步探索这个想法!
  • 我接受了这个答案,因为它真的很容易实现(使用计数器以及我的可选要求以秒为单位显示/倒计时)。再次感谢@Curtis Rutland!
  • 很高兴为您提供帮助。我发现通常情况下,第二个视角会为您提供您不会想到的简单解决方案,尤其是当您朝着不同的方向走下兔子洞时。
【解决方案2】:

在 windows 中有一个未记录的 MessageBoxTimeout 函数可供您使用:user32.dll 中的 MessageBoxTimeout(通过 PInvoke 使用)。

示例:

public class MessageBoxWithTimeout
{
  [DllImport("user32.dll", SetLastError = true)]
  [return: MarshalAs(UnmanagedType.U4)]
  private static extern uint MessageBoxTimeout(IntPtr hwnd,
    [MarshalAs(UnmanagedType.LPTStr)]  String text,
    [MarshalAs(UnmanagedType.LPTStr)] String title,
    [MarshalAs(UnmanagedType.U4)] uint type, 
    Int16 wLanguageId, 
    Int32 milliseconds);

  public static uint Show(IntPtr hWnd, string message, string caption, uint messageBoxOptions,Int32 timeOutMilliSeconds)
  {
     return MessageBoxTimeout(hWnd, message, caption, messageBoxOptions, 0, timeOutMilliSeconds);
  }
}

在您的代码中:

MessageBoxWithTimeout.Show( your parameters here );

但是,您应该考虑您的设计。根据定义,消息框会阻止您的对话框,因此多个消息框没有意义。如果您发布您的实际问题,也许有更好的解决方案。

【讨论】:

  • 嗨@nvoigt,谢谢你的回答和代码示例。我的应用程序有两种操作模式:1)用户主动输入表单,2)应用程序自动运行(监视文件夹的变化)。在这两种模式下,我都需要显示一个对话框(MessageBox)。当应用程序处于模式1)时,用户需要确认才能继续。在模式 2) 下,对话框应在 5 秒内自动关闭。因此,我很高兴 MessageBox 阻止了我的对话框(这是想要的),所有其他任务都使用线程在后台运行......我肯定会使用你的代码 sn-p (:
【解决方案3】:

以下代码可以作为起点。它基于我最近给出的related answer

async void MainForm_Load(object sender, EventArgs e)
{
    Func<Func<Form>, Task<Form>> showAsync = (createForm) =>
    {
        var tcs = new TaskCompletionSource<Form>();
        var form = createForm();
        form.Tag = Task.Factory.StartNew(
            () => form.ShowDialog(), 
            CancellationToken.None, 
            TaskCreationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext());
        form.Load += (sIgnore, eIgnore) =>
            tcs.TrySetResult(form);
        return tcs.Task;
    };

    var forms = new Stack<Form>();
    for (var i = 0; i < 4; i++)
        forms.Push(await showAsync((() =>
            new Form { Text = "Hello #" + i })));

    var closeFormTasks = forms.Select((form) => (Task)form.Tag);

    var delay = Task.Delay(5000);
    var task = await Task.WhenAny(delay, Task.WhenAll(closeFormTasks));

    if (task == delay)
    {
        while (forms.Any())
        {
            var form = forms.Pop();
            form.Close();
            await (Task)form.Tag;
        }
    }

    MessageBox.Show("All closed.");
}

【讨论】:

  • 嗨@Noseratio,非常感谢您分享这段代码!我真的很喜欢这个概念。但是,我会采用 Curtis Rutland 建议的解决方案(用普通的旧表单模仿 MessageBoxes)。
猜你喜欢
  • 1970-01-01
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多