Как обновить индикатор выполнения на один шаг, каждый цикл цикла?C # - PullRequest
3 голосов
/ 16 сентября 2010

Создание приложения .net в C #, окна формы. Как обновить индикатор выполнения на 1 шаг в каждом цикле цикла из 100 циклов? (Я обрабатываю лист Excel в цикле.) Элементы управления индикатора выполнения находятся в классе пользовательского интерфейса, который подключается к классу контроллера, который подключается к пользовательскому классу. (Шаблон MVC). Цикл находится в пользовательском классе. Нужно ли отправлять экземпляр класса пользовательского интерфейса в каждом методе полностью или есть лучший способ?

Прямо сейчас индикатор выполнения обновляется после завершения цикла. Application.doevents и .update или .refresh не работают.

Ответы [ 3 ]

5 голосов
/ 16 сентября 2010

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

sealed class Looper
{
    public event EventHandler ProgressUpdated;

    private int _progress;
    public int Progress
    {
        get { return _progress; }
        private set
        {
            _progress = value;
            OnProgressUpdated();
        }
    }

    public void DoLoop()
    {
        _progress = 0;
        for (int i = 0; i < 100; ++i)
        {
            Thread.Sleep(100);
            Progress = i;
        }
    }

    private void OnProgressUpdated()
    {
        EventHandler handler = ProgressUpdated;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

Вы можете реализовать это, имея BackgroundWorker как часть вашего пользовательского интерфейса, где в событии backgroundWorker.DoWork вы вызываете looper.DoLoop(). Затем в обработчике события looper.ProgressUpdated вы можете вызвать backgroundWorker.ReportProgress, чтобы увеличить индикатор выполнения из потока пользовательского интерфейса.

Обратите внимание, что, вероятно, было бы более разумно включить сам прогресс в информацию, переносимую вашим событием ProgressUpdated (мне просто не хотелось писать новый класс, производный от EventArgs, чтобы проиллюстрировать это; вы, вероятно, в любом случае получить изображение).

Также обратите внимание, что вышеприведенное действительно не имеет смысла, если вы не выполняете свой код с циклом в отдельном потоке от потока пользовательского интерфейса. В противном случае вся ваша работа будет завершена до следующего обновления пользовательского интерфейса, поэтому ваш индикатор выполнения не будет предоставлять никакого значения (он просто изменится с 0 до 100, когда цикл завершится).

Просто пример того, как такого рода вещи могут быть достигнуты.

1 голос
/ 16 сентября 2010

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

например. (предупреждение, псевдокод):

MyCustomClass class = new MyCustomClass();
class.ProgressUpdated += (s,e)=>{ /* update UI */};
class.StartLoop();
1 голос
/ 16 сентября 2010

У меня обычно есть один класс, который выполняет проверки вызовов в пользовательском интерфейсе. UI -> "UpdaterClass" -> другой класс.

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

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

Пример psuedocode:

class Updater()
{

  public ProgressBar pb;

  delegate void UpdateProgressBar();

  public StepProgressBar()
  {
     if(pb.InvokeRequired)
     {
          BeginInvoke(new UpdateProgressBar(this.StepProgressBar);
     }
     else
     {
          pb.Step();
      }
   }

}

Нечто подобное.

...