Показывать прогресс, только если фоновая операция длинная - PullRequest
5 голосов
/ 04 августа 2011

Я занимаюсь разработкой операции на C # и хотел бы показать модальное диалоговое окно прогресса, но только когда операция будет продолжительной (например, более 3 секунд).Я выполняю свои операции в фоновом потоке.

Проблема в том, что я не знаю заранее, будет ли операция длинной или короткой.

Некоторые программы, например IntelliJ имеет таймер доступа.Если операция занимает больше чем x раз, то покажите диалоговое окно.

Как вы думаете, что это хороший шаблон для реализации этого?

  • Ожидать поток пользовательского интерфейса с таймером, а там показывать диалог?
  • Должен ли я DoEvents() когда я показываю диалог?

Ответы [ 5 ]

4 голосов
/ 04 августа 2011

Вот что я бы сделал:

1) Используйте BackgroundWorker.

2) Перед вызовом метода RunWorkerAsync сохраните текущее время в переменной.

3) В событии DoWork вам нужно вызвать ReportProgress.В событии ProgressChanged проверьте, прошло ли время больше трех секунд.Если это так, покажите диалоговое окно.

Вот пример MSDN для BackgroundWorker: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

Примечание. В целом я согласен с комментарием Рэмхаунда.Просто всегда отображайте прогресс.Но если вы не используете BackgroundWorker, я бы начал его использовать.Это облегчит вашу жизнь.

4 голосов
/ 04 августа 2011

Я выберу первый вариант здесь с некоторыми изменениями:

Сначала запустите возможную длительную операцию в другом потоке.Затем запустите другой поток, чтобы проверить первый статус с помощью дескриптора ожидания с таймаутом, чтобы дождаться его завершения.если срабатывает тайм-аут, отображается индикатор выполнения.

Что-то вроде:

private ManualResetEvent _finishLoadingNotifier = new ManualResetEvent(false);

private const int ShowProgressTimeOut = 1000 * 3;//3 seconds


private void YourLongOperation()
{
    ....

    _finishLoadingNotifier.Set();//after finish your work
}

private void StartProgressIfNeededThread()
{
    int result = WaitHandle.WaitAny(new WaitHandle[] { _finishLoadingNotifier }, ShowProgressTimeOut);

    if (result > 1)
    {
        //show the progress bar.
    } 
}
2 голосов
/ 04 августа 2011

Если у вас есть методы DoPossiblyLongOperation(), ShowProgressDialog() и HideProgressDialog(), вы можете использовать TPL для выполнения тяжелой работы за вас:

var longOperation = new Task(DoPossiblyLongOperation).ContinueWith(() => myProgressDialog.Invoke(new Action(HideProgressDialog)));

if (Task.WaitAny(longOperation, new Task(() => Thread.Sleep(3000))) == 1)
    ShowProgressDialog();
0 голосов
/ 06 июля 2016

Рекомендуемое неблокирующее решение и не новые темы:

try
{
   var t = DoLongProcessAsync();
   if (await Task.WhenAny(t, Task.Delay(1000)) != t) ShowProgress();
   await t;
}
finally
{
   HideProgress();
}
0 голосов
/ 04 августа 2011

Я бы держал диалог прогресса отдельно от фоновой активности, чтобы отделить мою логику пользовательского интерфейса от остальной части приложения. Таким образом, последовательность будет (это по сути то же самое, что и IntelliJ):

  1. Пользовательский интерфейс запускает фоновую операцию (в BackgroundWorker) и устанавливает таймер на X секунд
  2. Когда таймер истекает, пользовательский интерфейс отображает диалоговое окно хода выполнения (если фоновая задача все еще выполняется)
  3. Когда фоновое задание завершается, таймер отменяется и диалоговое окно (если есть) закрывается

Использование таймера вместо отдельного потока является более ресурсоэффективным.

...