Frage

I am coding Windows Forms in C# under Visual Studio 2012 and I would like to open multiple instances of MessageBox and automatically close them after several seconds.

I have found (and upvoted) this answer here: SO: Close a MessageBox after several seconds.

However, this works if I only open 1 (one) MessageBox at a time, since it makes use of the function FindWindow, and the multiple instances of my MessageBox shall have all the same window title (caption).

[Optionally] In addition, I would like to present the user with a countdown, like This dialog will close in 5 seconds, This [...] in 4 seconds, This [...] in 3 seconds, ..., This [...] in 1 seconds and then finally close the MessageBox.

Is there a way to uniquely reference my multiple MessageBoxes and automatically close them (either using System.Timers.Timer or System.Threading.Timer or System.Windows.Forms.Timer - whichever is the best fit for this solution) after a certain period of time (say 5 seconds)?

War es hilfreich?

Lösung

I suggest not using a MessageBox for this task. Instead, make your own custom form. Make it the size, shape, and look you want. Then, in its code-behind file, you can create a timer, unique to that window itself. That way, you can spawn as many of them as you want, and they will manage their own timers and closing themselves, and you don't have to do anything like finding the window. It's possible to make a Form look very much like a MessageBox. And because you can call ShowDialog, you can make them behave similarly to MessageBoxes as well (though that would be somewhat counterproductive, because you can only interact with one dialog at a time).

Andere Tipps

There is an undocumented MessageBoxTimeout function in windows that you could use: MessageBoxTimeout in user32.dll (use via PInvoke).

Example:

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

In your code:

MessageBoxWithTimeout.Show( your parameters here );

However, you should think about your design. A message box by definition is blocking your dialog, so multiple messageboxes do not make sense. If you post your actual problem, maybe there is a better solution.

The following code can be used a as a starting point. It's based on the related answer I gave recently.

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.");
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top