Вы можете использовать методы маршалинга, такие как 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
каждый раз, когда вам нужно обновить пользовательский интерфейс из рабочего потока.