Откройте несколько экземпляров MessageBox и автоматически закройте через несколько секунд

Я пишу Windows Forms в C# под Visual Studio 2012, и я хотел бы открыть несколько экземпляров MessageBox и автоматически закрыть их через несколько секунд.

Я нашел (и проголосовал) этот ответ здесь: SO: Закрыть MessageBox через несколько секунд.

Тем не менее, это работает, если я только открываю 1 (один) MessageBox за раз, так как он использует функцию FindWindowи несколько экземпляров моего MessageBox должны иметь одинаковый заголовок окна (заголовок).

[Необязательно] Кроме того, я хотел бы представить пользователю обратный отсчет, например: этот диалог закроется через 5 секунд, этот [...] через 4 секунды, этот [...] через 3 секунды,..., Это [...] через 1 секунду, а затем, наконец, закройте MessageBox.

Есть ли способ однозначно ссылаться на несколько моих MessageBox и автоматически закрывать их (используя System.Timers.Timer или же System.Threading.Timer или же System.Windows.Forms.Timer - какой из них лучше всего подходит для этого решения) через определенный промежуток времени (скажем, 5 секунд)?

3 ответа

Решение

Я предлагаю не использовать MessageBox для этой задачи. Вместо этого сделайте свою собственную форму. Сделайте размер, форму и внешний вид, какой хотите. Затем в его файле с выделенным кодом вы можете создать таймер, уникальный для самого этого окна. Таким образом, вы можете создавать их столько раз, сколько захотите, и они будут управлять своими таймерами и закрывать себя, и вам не нужно будет ничего делать, как найти окно. Можно сделать форму очень похожей на MessageBox. И поскольку вы можете вызывать ShowDialog, вы можете заставить их вести себя аналогично MessageBoxes (хотя это было бы несколько контрпродуктивно, потому что вы можете взаимодействовать только с одним диалогом одновременно).

В Windows есть недокументированная функция MessageBoxTimeout, которую вы можете использовать: MessageBoxTimeout в user32.dll (используйте через 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 );

Тем не менее, вы должны подумать о своем дизайне. Окно сообщений по определению блокирует ваше диалоговое окно, поэтому несколько ящиков сообщений не имеют смысла. Если вы разместите вашу актуальную проблему, возможно, есть лучшее решение.

Следующий код можно использовать в качестве отправной точки. Это основано на связанном ответе, который я дал недавно.

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.");
}
Другие вопросы по тегам