отложить применение Закрыть лучшие практики? - PullRequest
0 голосов
/ 19 января 2010

Есть ли лучший способ для решения задачи сделать что-то после того, как пользователь выбрал выход из программы WinForms, чем этот:

[править 1: в ответ на комментарий 'NoBugz ] В этом случае в форме нет ControlBox , и есть причина для включения одного уровня косвенности в что происходит, когда пользователь решает закрыть форму [/ edit 1]

[править 2: в ответ на все комментарии по Гринвичу +7 18:35 января 20 ] Возможно, использование затухания MainForm - простая иллюстрация того, что вы можете захотеть делать так, как приложение закрывается: пользователь не может с этим взаимодействовать: это, очевидно, связано с решением пользователя закрыть приложение. [/ edit 2]

(использовать какую-либо форму многопоточности?) (Значение для многопоточного приложения?) (Этот код "плохо пахнет"?)

    // 'shutDown is an external form-scoped boolean variable
    //
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        // make sure we don't block Windows ShutDown
        // or other valid reasons to close the Form
        if (e.CloseReason != CloseReason.ApplicationExitCall) return;

        // test for 'shutDown flag set here
        if (shutDown) return;

        // cancel closing the Form this time through
        e.Cancel = true;

        // user choice : default = 'Cancel
        if (MessageBox.Show("Exit Application ?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.OK)
        {
            // user says Exit : activate Timer, set the flag to detect Exit
            timer1.Enabled = true;
            shutDown = true;
        }
    }

Резюме: в очень стандартном приложении WinForms (одна MainForm, запущенная в Program.cs стандартным способом): в обработчике события FormClosing MainForm:

  1. немедленно завершить работу (вызывая поведение по умолчанию: закрытие MainForm и выход из приложения), если:

    а. CloseReason - это что-то другое CloseReason.ApplicationExitCall

    б. если для специальной логической переменной задано значение true или

  2. если нет немедленного выхода: отмените «первый звонок» в FormClosing.

  3. пользователь затем делает выбор, через диалоговое окно MessageBox.Show, выйти из приложения или отменить:

    а. если пользователь отменяет, конечно, приложение остается «как есть».

    б. если пользователь выбрал «Выход»:

    1. установить для переменной специального логического флага значение true

    2. запустить таймер, который делает что-то особенное.

    3. когда внутренний тест в коде таймера обнаруживает, что «особые вещи» выполнены, он вызывает Application.Exit

Ответы [ 3 ]

7 голосов
/ 20 января 2010

Мои предложения как разработчика, так и пользователя:

Очень быстрое задание

  • Просто выполните задачу в обработчике закрытия.

Менее быстрая, но не невероятно медленная задача

  • Создайте не фоновый поток (чтобы он не закрывался при выходе из приложения) с задачей в обработчике закрытия.
  • Дайте приложению выйти. Формы исчезнут и так далее, но процесс будет продолжаться до тех пор, пока задача не будет выполнена.
  • Только не забудьте обработать исключения и тому подобное в этом рабочем потоке. И убедитесь, что ничего не выйдет из строя, если пользователь снова откроет ваше приложение до выполнения этой задачи.

Медленные задачи

  • В обработчике событий Closing откройте форму выключения и дайте форме закрыться.
  • Выполните задание в / за форме выключения, отображая некоторый дружественный прогресс и информацию.
  • Выйдите из приложения, когда задача будет выполнена.

Некоторые примеры кода, не проверенные. Мы делаем нечто подобное в одном из наших приложений. Задача в нашем случае - сохранить свойства окна (местоположение, размер, состояние окна и т. Д.) В базе данных.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    // If it wasn't the user who asked for the closing, we just close
    if (e.CloseReason != CloseReason.UserClosing)
        return;

    // If it was the user, we want to make sure he didn't do it by accident
    DialogResult r = MessageBox.Show("Are you sure you want this?", 
                                     "Application is shutting down.",
                                     MessageBoxButtons.YesNo, 
                                     MessageBoxIcon.Question);
    if (r != DialogResult.Yes)
    {
        e.Cancel = true;
        return;
    }
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
    // Start the task
    var thread = new Thread(DoTask)
    {
        IsBackground = false,
        Name = "Closing thread.",
    };
    thread.Start();

    base.OnFormClosed(e);
}

private void DoTask()
{
    // Some task to do here
}
2 голосов
/ 19 января 2010

Я не вижу в этом ничего "неправильного". Моя единственная рекомендация - дать пользователю знать, что программа «закрывается», подняв немодальное окно или, возможно, тостер уведомлений над панелью задач.

0 голосов
/ 19 января 2010

Пара незначительных очков:

  • Я бы поставил под сомнение необходимость таймера: поскольку приложение все равно завершается, и пользователь не будет ожидать, что пользовательский интерфейс будет отзывчивым, почему бы просто не выполнить код очистки потока UI ? Как предложил @Dave Swersky, небольшое окно уведомлений во время очистки будет вежливым.

  • Что произойдет, если выход из приложения будет вызван завершением работы Windows или выходом пользователя из системы?

...