在 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 编辑过