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