Обновление индикатора выполнения из другого потока - PullRequest
3 голосов
/ 29 мая 2009

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

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

Ответы [ 3 ]

3 голосов
/ 24 мая 2012

Вы можете использовать методы маршалинга, такие как 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;
  }
}

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

  • Поток пользовательского интерфейса определяет, когда и как часто пользовательский интерфейс обновляется ... каким он должен быть!
  • Рабочий поток не должен ждать ответа от потока пользовательского интерфейса, прежде чем он сможет продолжить работу, как в случае с Invoke.
  • Это нарушает тесную связь между пользовательским интерфейсом и рабочими потоками, которую навязывает Invoke.
  • Это более эффективно ... значительно.
  • Вы получаете большую пропускную способность как для пользовательского интерфейса, так и для рабочих потоков.
  • Нет шансов насытить очередь сообщений интерфейса пользователя, как это может быть в случае BeginInvoke.
  • Вам не нужно засорять свой код вызовами Invoke каждый раз, когда вам нужно обновить пользовательский интерфейс из рабочего потока.
2 голосов
/ 29 мая 2009

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

1 голос
/ 29 мая 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...