在 C# WinForms 中,多线程之间的通信有多种方式。
- 使用Control.Invoke或Control.BeginInvoke方法(适用于WinForms)
- 使用BackgroundWorker组件(较老的方法,但现在仍然可用)
- 使用async/await模式(推荐,特别是对于I/O密集型操作)
- 使用事件(Event)和同步上下文(SynchronizationContext)
1. 使用 Control.Invoke/BeginInvoke(最常用)
原理说明
WinForms 控件不是线程安全的,必须在其创建的线程(UI线程)上访问。Invoke
和 BeginInvoke
用于将方法调用封送到UI线程。
代码示例
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Multi_Thread_Communication
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void LogMessage(string message)
{
if (this.textBoxLog.InvokeRequired)
{
this.textBoxLog.BeginInvoke(new Action<string>(LogMessage), message);
}
else
{
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
this.textBoxLog.AppendText($"[{timestamp}] {message}\r\n");
}
}
private void UpdateProgressBar(int value)
{
if (this.progressBar.InvokeRequired)
{
this.progressBar.BeginInvoke(new Action<int>(UpdateProgressBar), value);
}
else
{
this.progressBar.Value = value;
}
}
private void WorkerMethod()
{
LogMessage($"工作线程开始 - 线程ID: {Thread.CurrentThread.ManagedThreadId}");
for (int i = 1; i <= 5; i++)
{
Thread.Sleep(1000);
LogMessage($"处理第 {i} 项任务...");
}
LogMessage("工作线程完成");
}
private void WorkerWithProgress()
{
for (int i = 0; i <= 100; i += 10)
{
Thread.Sleep(500);
UpdateProgressBar(i);
LogMessage($"进度: {i}%");
}
}
private void btnStartWorker_Click(object sender, EventArgs e)
{
LogMessage("主线程ID: " + Thread.CurrentThread.ManagedThreadId);
Thread workerThread = new Thread(new ThreadStart(WorkerMethod));
workerThread.IsBackground = true;
workerThread.Start();
}
private void btnStartWithProgress_Click(object sender, EventArgs e)
{
Thread progressThread = new Thread(new ThreadStart(WorkerWithProgress));
progressThread.IsBackground = true;
progressThread.Start();
}
}
}

2. 使用 BackgroundWorker 组件
原理说明
BackgroundWorker
是专门为WinForms设计的后台工作组件,内置了线程安全的事件机制。
代码示例
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace WinFormsThreadCommunication
{
public partial class BackgroundWorkerForm : Form
{
private TextBox textBoxLog;
private Button btnStart;
private ProgressBar progressBar;
private BackgroundWorker backgroundWorker;
public BackgroundWorkerForm()
{
InitializeComponent();
InitializeBackgroundWorker();
}
private void InitializeComponent()
{
this.textBoxLog = new TextBox();
this.btnStart = new Button();
this.progressBar = new ProgressBar();
this.textBoxLog.Multiline = true;
this.textBoxLog.ScrollBars = ScrollBars.Vertical;
this.textBoxLog.Dock = DockStyle.Fill;
this.textBoxLog.ReadOnly = true;
this.btnStart.Text = "启动 BackgroundWorker";
this.btnStart.Dock = DockStyle.Top;
this.progressBar.Dock = DockStyle.Bottom;
this.progressBar.Height = 30;
this.Controls.Add(this.textBoxLog);
this.Controls.Add(this.btnStart);
this.Controls.Add(this.progressBar);
this.Size = new System.Drawing.Size(500, 400);
this.Text = "BackgroundWorker 示例";
this.btnStart.Click += BtnStart_Click;
}
private void InitializeBackgroundWorker()
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
}
private void BtnStart_Click(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
{
btnStart.Enabled = false;
backgroundWorker.RunWorkerAsync();
}
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 0; i <= 100; i += 10)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i, $"处理进度: {i}%");
}
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
textBoxLog.AppendText($"{e.UserState}\r\n");
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnStart.Enabled = true;
if (e.Cancelled)
{
textBoxLog.AppendText("操作被取消\r\n");
}
else if (e.Error != null)
{
textBoxLog.AppendText($"发生错误: {e.Error.Message}\r\n");
}
else
{
textBoxLog.AppendText("操作完成\r\n");
}
}
}
}

3. 使用async/await
原理说明
使用 async/await模式
,可以编写异步代码,而不会阻塞UI线程,并且可以在异步操作完成后直接更新UI,因为 await
后面的代码会在UI线程上执行(如果在UI线程上启动的话)。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormsThreadCommunication
{
public partial class Form1 : Form
{
private System.Threading.CancellationTokenSource cancellationTokenSource;
public Form1()
{
InitializeComponent();
InitButtonPanel();
}
private void InitButtonPanel()
{
buttonPanel.Controls.Add(this.btnCancelOperation);
buttonPanel.Controls.Add(this.btnStartMultiple);
buttonPanel.Controls.Add(this.btnStartAsync);
buttonPanel.Height = 90;
this.Text = "async/await 示例";
}
private void LogMessage(string message)
{
if (this.textBoxLog.InvokeRequired)
{
this.textBoxLog.BeginInvoke(new Action<string>(LogMessage), message);
}
else
{
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
this.textBoxLog.AppendText($"[{timestamp}] {message}\r\n");
}
}
private async void btnStartAsync_Click(object sender, EventArgs e)
{
LogMessage("开始异步操作...");
btnStartAsync.Enabled = false;
try
{
var progress = new Progress<int>(percent =>
{
progressBar.Value = percent;
LogMessage($"进度更新: {percent}%");
});
string result = await DoAsyncWork(progress);
LogMessage($"操作完成: {result}");
await StartCancellableWork();
}
catch (OperationCanceledException)
{
LogMessage("操作被取消");
}
catch (Exception ex)
{
LogMessage($"操作出错: {ex.Message}");
}
finally
{
btnStartAsync.Enabled = true;
}
}
private async void btnStartMultiple_Click(object sender, EventArgs e)
{
LogMessage("开始多个异步任务...");
btnStartMultiple.Enabled = false;
try
{
var task1 = DoAsyncWorkWithName("任务A", 1000);
var task2 = DoAsyncWorkWithName("任务B", 1500);
var task3 = DoAsyncWorkWithName("任务C", 800);
string[] results = await Task.WhenAll(task1, task2, task3);
foreach (string result in results)
{
LogMessage($"任务结果: {result}");
}
LogMessage("所有任务完成!");
}
catch (Exception ex)
{
LogMessage($"任务出错: {ex.Message}");
}
finally
{
btnStartMultiple.Enabled = true;
}
}
private async Task<string> DoAsyncWork(IProgress<int> progress)
{
return await Task.Run(() =>
{
for (int i = 0; i <= 100; i += 10)
{
if (cancellationTokenSource?.Token.IsCancellationRequested == true)
{
throw new OperationCanceledException();
}
System.Threading.Thread.Sleep(200);
progress?.Report(i);
}
return "异步工作完成";
});
}
private async Task<string> DoAsyncWorkWithName(string taskName, int delay)
{
LogMessage($"开始 {taskName}");
await Task.Run(() =>
{
System.Threading.Thread.Sleep(delay);
});
LogMessage($"完成 {taskName}");
return $"{taskName} 结果 (延迟: {delay}ms)";
}
private async Task StartCancellableWork()
{
cancellationTokenSource = new System.Threading.CancellationTokenSource();
btnCancelOperation.Enabled = true;
try
{
var progress = new Progress<int>(percent =>
{
progressBar.Value = percent;
LogMessage($"可取消任务进度: {percent}%");
});
string result = await DoCancellableWorkAsync(progress, cancellationTokenSource.Token);
LogMessage($"可取消任务完成: {result}");
}
catch (OperationCanceledException)
{
LogMessage("任务已被取消");
}
finally
{
btnCancelOperation.Enabled = false;
cancellationTokenSource = null;
}
}
private async Task<string> DoCancellableWorkAsync(IProgress<int> progress, System.Threading.CancellationToken cancellationToken)
{
return await Task.Run(() =>
{
for (int i = 0; i <= 100; i += 5)
{
cancellationToken.ThrowIfCancellationRequested();
System.Threading.Thread.Sleep(100);
progress?.Report(i);
}
return "可取消任务完成";
}, cancellationToken);
}
private void btnCancelOperation_Click(object sender, EventArgs e)
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
btnCancelOperation.Enabled = false;
LogMessage("正在取消操作...");
}
}
}
}

4. 使用事件(Event)机制
原理说明
通过自定义事件在不同线程间传递数据。
代码示例
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormsThreadCommunication
{
public partial class Form1 : Form
{
public event EventHandler<ProgressEventArgs> ProgressUpdated;
public Form1()
{
InitializeComponent();
this.ProgressUpdated += OnProgressUpdated;
}
private void btnStart_Click(object sender, EventArgs e)
{
Thread workerThread = new Thread(new ThreadStart(WorkerWithEvents));
workerThread.IsBackground = true;
workerThread.Start();
}
private void WorkerWithEvents()
{
for (int i = 0; i <= 100; i += 10)
{
Thread.Sleep(400);
OnProgressUpdated(this, new ProgressEventArgs(i, $"事件进度: {i}%"));
}
}
protected virtual void OnProgressUpdated(object sender, ProgressEventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action<object, ProgressEventArgs>(OnProgressUpdated), sender, e);
return;
}
progressBar.Value = e.Percentage;
textBoxLog.AppendText($"{e.Message}\r\n");
}
}
public class ProgressEventArgs : EventArgs
{
public int Percentage { get; set; }
public string Message { get; set; }
public ProgressEventArgs(int percentage, string message)
{
Percentage = percentage;
Message = message;
}
}
}

关键点
- 线程安全:WinForms控件只能在创建它们的线程(UI线程)上访问
- InvokeRequired
- Invoke/BeginInvoke
- BackgroundWorker:专门为WinForms设计的后台工作组件,使用更简单
- 事件机制
阅读原文:原文链接
该文章在 2025/10/20 12:15:57 编辑过