LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# WinForms 多线程通信的方法

admin
2025年10月19日 1:27 本文热度 100

在 C# WinForms 中,多线程之间的通信有多种方式。

  1. 使用Control.Invoke或Control.BeginInvoke方法(适用于WinForms)
  2. 使用BackgroundWorker组件(较老的方法,但现在仍然可用)
  3. 使用async/await模式(推荐,特别是对于I/O密集型操作)
  4. 使用事件(Event)和同步上下文(SynchronizationContext)

1. 使用 Control.Invoke/BeginInvoke(最常用)

原理说明

WinForms 控件不是线程安全的,必须在其创建的线程(UI线程)上访问。Invoke 和 BeginInvoke 用于将方法调用封送到UI线程。

  • Invoke
    :同步调用,会阻塞当前线程直到UI线程执行完成
  • BeginInvoke
    :异步调用,立即返回

代码示例

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)        {            // 检查是否需要Invoke            if (this.textBoxLog.InvokeRequired)            {                // 使用BeginInvoke进行异步调用                this.textBoxLog.BeginInvoke(new Action<string>(LogMessage), message);            }            else            {                // 在UI线程上执行                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);                // 更新进度条 - 必须使用Invoke                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(500400);            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)        {            // 这些代码在UI线程上执行,不需要Invoke            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            {                // 使用 IProgress 进行进度报告                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;            }        }        // 异步工作方法 - 使用 IProgress 报告进度        private async Task<stringDoAsyncWork(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);                    // 报告进度,更新UI                    progress?.Report(i);                }                return "异步工作完成";            });        }        // 带名称的异步工作        private async Task<stringDoAsyncWorkWithName(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<stringDoCancellableWorkAsync(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(thisnew ProgressEventArgs(i, $"事件进度: {i}%"));            }        }        // 事件处理方法        protected virtual void OnProgressUpdated(object sender, ProgressEventArgs e)        {            // 检查是否需要Invoke到UI线程            if (this.InvokeRequired)            {                this.BeginInvoke(new Action<object, ProgressEventArgs>(OnProgressUpdated), sender, e);                return;            }            // 在UI线程上更新控件            progressBar.Value = e.Percentage;            textBoxLog.AppendText($"{e.Message}\r\n");        }    }    // 自定义事件参数    public class ProgressEventArgs : EventArgs    {        public int Percentage { getset; }        public string Message { getset; }        public ProgressEventArgs(int percentage, string message)        {            Percentage = percentage;            Message = message;        }    }}

关键点

  1. 线程安全
    :WinForms控件只能在创建它们的线程(UI线程)上访问
  2. InvokeRequired
    :检查当前线程是否是控件的创建线程
  3. Invoke/BeginInvoke
    :将方法调用封送到UI线程
  4. BackgroundWorker
    :专门为WinForms设计的后台工作组件,使用更简单
  5. 事件机制
    :通过自定义事件实现松耦合的线程通信


阅读原文:原文链接


该文章在 2025/10/20 12:15:57 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved