Обновление индикатора выполнения из другого потока

У меня есть форма окна в основном потоке и еще один поток, который выполняет некоторые вычисления. Я хотел бы обновить строку состояния в моей форме из работы, выполняемой в другом потоке. Как лучше всего это сделать?

До сих пор все, что я пробовал, просто замедляло работу. Я использую Visual Studio 2005.


person MrDatabase    schedule 29.05.2009    source источник
comment
Вы должны быть более конкретными - что было медленным? как вы используете нитки?   -  person Nikolai Fetissov    schedule 29.05.2009


Ответы (3)


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

person Rob    schedule 29.05.2009

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

На сегодняшний день лучший способ сделать это:

  • Пусть ваш рабочий поток публикует информацию о ходе выполнения в общей переменной.
  • Попросите ваш поток пользовательского интерфейса опросить его через System.Windows.Forms.Timers с интервалом, который удобен для вас.

Вот как это может выглядеть.

public class Example : Form
{
  private volatile int percentComplete = 0;

  private void StartThreadButton_Click(object sender, EventArgs args)
  {
    StatusBarUpdateTimer.Enabled = true;
    new Thread(
      () =>
      {
        for (int i = 1; i <= 100; i++)
        {
          DoSomeWork();
          percentComplete = i;
        }
      }).Start();
  }

  private void StatusBarUpdateTimer_Tick(object sender, EventArgs args)
  {
    yourStatusBarPanel.Text = percentComplete.ToString() + "%";
    StatusBarUpdateTimer.Enabled = percentComplete < 100;
  }
}

Это хорошо работает, потому что:

  • Поле PercentComplete объявлено «изменчивым», что гарантирует возможность надежного чтения его значения из нескольких потоков.
  • Поток пользовательского интерфейса должен диктовать, когда и как часто будет обновляться пользовательский интерфейс... так, как это должно быть!
  • Рабочий поток не должен ждать ответа от потока пользовательского интерфейса, прежде чем он сможет продолжить работу, как в случае с Invoke.
  • Это разрушает тесную связь между пользовательским интерфейсом и рабочими потоками, которую навязывает Invoke.
  • Это более эффективно... значительно.
  • Вы получаете большую пропускную способность как в пользовательском интерфейсе, так и в рабочих потоках.
  • Нет возможности переполнить очередь сообщений пользовательского интерфейса, как это может быть в случае с BeginInvoke.
  • Вам не нужно засорять свой код вызовами Invoke каждый раз, когда вам нужно обновить пользовательский интерфейс из рабочего потока.
person Brian Gideon    schedule 24.05.2012

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

person Colen    schedule 29.05.2009