С# Progress Bar не сотрудничает

Я столкнулся с очень странной ситуацией. Это должно быть так просто, но я не уверен, почему это происходит.

У меня есть индикатор выполнения бегущей строки, установленный на visible=false в качестве исходного состояния. Затем в какой-то момент во время выполнения я вызываю одну из своих функций и прямо перед ее вызовом устанавливаю для PB значение visible=true, а после завершения функции снова устанавливаю значение visible=false. Это не становится проще, чем это.

If (something)
{
  pb.visible=true;
  runMyfunction(x, x, x, x,);
  pb.visible=false;
}

Проблема в том, что я никогда не вижу ПБ. Если я закомментирую свою функцию и удалю =false, появится PB, но как только я верну туда свою функцию, PB никогда не появится.

Я пробовал разные подходы. Использование операторов If, чтобы убедиться, что я получаю индикатор выполнения, прежде чем он когда-либо коснется функции, и он по-прежнему скрывает PB.

Я что-то пропустил? Это не похоже на то, что это должно быть так сложно. Показать объект, запустить функцию, скрыть объект. Верно? :)


person GeneK    schedule 11.03.2011    source источник
comment
Это winforms или asp.net или WPF или что?   -  person kprobst    schedule 11.03.2011
comment
Вы имеете в виду индикатор выполнения WinForms ASP.NET?   -  person TheBoyan    schedule 11.03.2011


Ответы (4)


Я предполагаю, что myRunFunction() работает в потоке пользовательского интерфейса.

Попробуйте запустить его внутри BackgroundWorker и запустите ProgressBar перед вызовом RunWorkerAsync и остановите его. в событии RunWorkerCompleted.

Отредактировано с примером кода:

public class SomeClass
{
    private BackgroundWorker _myFunctionBackgroundWorker;
    private SomeProgressBar pb;

    public SomeClass()
    {
        _myFunctionBackgroundWorker = new BackgroundWorker();
        _myFunctionBackgroundWorker.DoWork += myFunctionBackgroundWorker_DoWork;
        _myFunctionBackgroundWorker.RunWorkerCompleted += myFunctionBackgroundWorker_RunWorkerCompleted;

        pb.visible = true;
        _myFunctionBackgroundWorker.RunWorkerAsync();
    }

    private void myFunctionBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        runMyfunction();
    }


    private void myFunctionBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        pb.visible = false;
    }
}
person Olav Haugen    schedule 11.03.2011
comment
Работал как шарм! Спасибо. Однако есть одна проблема. В моей функции есть несколько операторов catch, и когда она попадает в них, я получаю ошибку перекрестного потока. Я предполагаю, что по какой-то причине они не инкапсулируются в исходный поток, запущенный фоновым рабочим. В любом случае, я могу это исправить? - person GeneK; 11.03.2011
comment
Неважно, я понял. Пришлось немного изменить мою функцию, но как только я передал все свои результаты в e.Result, все работает отлично! Еще раз спасибо за то, что помогли мне настроить правильный подход с помощью backgroundworker. - person GeneK; 11.03.2011

Это потому, что ваша функция связывает поток пользовательского интерфейса. Установка ProgressBar на видимый требует, чтобы поток пользовательского интерфейса был освобожден для его рисования, но вместо этого вы продолжаете обрабатывать свою функцию, которая никогда не дает ей времени для рисования.

Вы можете обойти это, вызвав: Application.DoEvents Что останавливает обработку вашего метода на время, достаточное для обработки некоторых сообщений Windows (и выполнения соответствующего рисунка).

Большая проблема с Application.DoEvents заключается в том, что если вы обновляете индикатор выполнения из runMyfunction(), вам придется постоянно вызывать Application.DoEvents, чтобы позволить вашему PB рисовать, иначе вы увидите его, но никогда не увидите, как он обновляется. .

Лучшее решение — отправить вызов runMyfunction() в фоновый поток и оттуда асинхронно обновить индикатор выполнения. Это, конечно, намного сложнее, но обеспечивает лучший пользовательский опыт.

person CodingGorilla    schedule 11.03.2011
comment
BackgroundWorker может быть идеальным для этой ситуации. Он инкапсулирует множество методов, которые вам понадобятся. - person ChrisG; 11.03.2011
comment
Это здорово, так как решает проблему. Но, поскольку мое приложение все еще привязано, пока функция работает ~ 10 секунд, бегущая строка никогда не перемещается. Я просто делаю простую маршрутизацию, показывающую бегущую строку во время работы функции, а затем удаляю ее в конце. Я собираюсь попробовать предложение ROBOlav, используя backgroundworker. - person GeneK; 11.03.2011

внутри вашего вызова метода runMyFunction() Application.DoEvents(), чтобы заставить ваше приложение перерисовать и обработать цикл сообщений Windows:

e.g.

void myRunFunction()
{
  while (someFlag)
  {
   // do work
   pb.Value = someValue;
   Application.DoEvents();
  }
}
person Mike Marshall    schedule 11.03.2011

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

person Tony Abrams    schedule 11.03.2011