C# 一个线程访问另外一个线程的控件(线程之间的控件的互相访问)

1 篇文章 0 订阅

本文以一个线程实时动态的改变主线程上面的label的text值为例子

步骤

  1. 新建项目和添加事件
  2. 核心代码书写

新建项目和添加事件

首先在窗口上面添加一个label两个按钮(分别用来开始子线程和终止子线程)
在这里插入图片描述

然后为两个按钮添加click事件
在这里插入图片描述

核心代码的书写

在代码区的窗口类下面添加一个BackgroundWorker控件(注意添加命名空间using System.ComponentModel;)
BackgroundWorker可以当它就是一个子线程
在这里插入图片描述
在button2的click事件 配置子线程(包括子线程执行的函数等)
为子线程添加 工作函数BackWorker_DoWork和能够访问主线程的BackWorker_ProgressChanged函数

    //点击button2 配置子线程(包括子线程执行的函数等)
        private void button2_Click(object sender, EventArgs e)
        {
            //为子线程添加需要执行的函数
            backWorker.DoWork += BackWorker_DoWork;

            //开始执行函数 并且传入一个参数 100
            backWorker.RunWorkerAsync(100);

            //指示是否在执行过程中可以 调用ProgressChanged函数
            backWorker.WorkerReportsProgress = true;

            //添加需要执行的ProgressChanged函数(该函数是子线程控制主线程的关键函数,我们不能在DoWork函数中访问其他主线程的控件但是在ProgressChanged函数中可以)
            backWorker.ProgressChanged += BackWorker_ProgressChanged;

            //指示子线程是否可以被终止
            backWorker.WorkerSupportsCancellation = true;

        }

然后再为任务添加内容
内容是 循环计算1加到100的求和 将 每次循环 求和的结果先发送到BackWorker_ProgressChanged函数中
因为我们不能在BackWorker_DoWork这个工作函数中访问主线程的控件,只能在BackWorker_ProgressChanged函数
(注意Thread类需要用到的命名空间是using System.Threading;)

 //子线程需要执行的函数
        private void BackWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //获取执行这个函数的线程
            BackgroundWorker bgWorker = sender as BackgroundWorker;

            //用end获取传进来的参数 
            int end = 0;
            if (e.Argument != null)
            {
                end = (int)e.Argument;
            }

            //函数的注意作用是循环执行下面的计算操作
            int sum = 0;
            for (int i = 0; i <= end; i++)
            {
                //计算操作
                sum += i;

                string text = "现在的计算结果是: " + sum.ToString();

                //调用BackWorker_ProgressChanged函数(该函数可以访问主线程的控件,实现线程之间的访问主要靠它)
                //并且返回本次循环的计算结果到BackWorker_ProgressChanged函数
                bgWorker.ReportProgress(i, text);

                //子线程暂停600毫秒,避免过快计算,看不出效果
                Thread.Sleep(600);

                //每次循环都检测 用户是否点击了button1按钮也就是终止子线程的按钮
                //当BackgroundWorker类调用了CancelAsync()方法就会使得BackgroundWorker类的CancellationPending值为true
                if (bgWorker.CancellationPending == true)
                {
                    //正式终止本线程
                    e.Cancel = true;
                    break;
                }
            }
        }

然后在BackWorker_ProgressChanged函数中将发送过来的结果赋值到label控件上实现对主线程的访问

        private void BackWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //获取每次循环的计算结果
            string text = e.UserState.ToString();
            this.label1.Text = text;
        }

最后在button1的click函数中添加终止子线程的方法

        //点击button1 提出终止子线程申请
        private void button1_Click(object sender, EventArgs e)
        {
            //向backWorker线程提出 要终止backWorker线程,但并非正式终止该线程
            //调用的下面的方法以后 该线程的CancellationPending属性的值 将等于 true 以此来知道提出了终止申请
            backWorker.CancelAsync();
            //只有在提出终止申请以后执行  e.Cancel = true;   语句子线程才能真正终止
        }

下面是所有代码的展示

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;

using System.Threading;

namespace progressBar_text
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //新建一个BackgroundWorker实例(新建一个子线程backWorker)
        BackgroundWorker backWorker = new BackgroundWorker();


        //点击button2 配置子线程(包括子线程执行的函数等)
        private void button2_Click(object sender, EventArgs e)
        {
            //为子线程添加需要执行的函数
            backWorker.DoWork += BackWorker_DoWork;

            //开始执行函数 并且传入一个参数 100
            backWorker.RunWorkerAsync(100);

            //指示是否在执行过程中可以 调用ProgressChanged函数
            backWorker.WorkerReportsProgress = true;

            //添加需要执行的ProgressChanged函数(该函数是子线程控制主线程的关键函数,我们不能在DoWork函数中访问其他主线程的控件但是在ProgressChanged函数中可以)
            backWorker.ProgressChanged += BackWorker_ProgressChanged;

            //指示子线程是否可以被终止
            backWorker.WorkerSupportsCancellation = true;

        }

        //点击button1 提出终止子线程申请
        private void button1_Click(object sender, EventArgs e)
        {
            //向backWorker线程提出 要终止backWorker线程,但并非正式终止该线程
            //调用的下面的方法以后 该线程的CancellationPending属性的值 将等于 true 以此来知道提出了终止申请
            backWorker.CancelAsync();
            //只有在提出终止申请以后执行  e.Cancel = true;   语句子线程才能真正终止
        }


        //子线程需要执行的函数
        private void BackWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //获取执行这个函数的线程
            BackgroundWorker bgWorker = sender as BackgroundWorker;

            //用end获取传进来的参数 
            int end = 0;
            if (e.Argument != null)
            {
                end = (int)e.Argument;
            }

            //函数的注意作用是循环执行下面的计算操作
            int sum = 0;
            for (int i = 0; i <= end; i++)
            {
                //计算操作
                sum += i;

                string text = "现在的计算结果是: " + sum.ToString();

                //执行ReportProgress函数(该函数可以访问主线程的控件,实现线程之间的访问主要靠它)
                //并且返回本次循环的计算结果
                bgWorker.ReportProgress(i, text);

                //子线程暂停600毫秒,避免过快计算,看不出效果
                Thread.Sleep(600);

                //每次循环都检测 用户是否点击了button1按钮也就是终止子线程的按钮
                //当BackgroundWorker类调用了CancelAsync()方法就会使得BackgroundWorker类的CancellationPending值为true
                if (bgWorker.CancellationPending == true)
                {
                    //正式终止本线程
                    e.Cancel = true;
                    break;
                }
            }
        }
        private void BackWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //获取每次循环的计算结果
            string text = e.UserState.ToString();
            this.label1.Text = text;
        }

    }
}

参考文献
https://www.cnblogs.com/sparkdev/p/5906272.html

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C# 中,可以通过 `Thread` 类来创建线程,并在线程中更新 `Chart` 控件的数值。具体实现步骤如下: 1. 在窗体上添加 `Chart` 控件,并设置其 `ChartType` 属性为 `SeriesChartType.Line`。 2. 在窗体的构造函数中启动一个线程,该线程每隔一段时间随机生成一个数值,并通过 `Invoke` 方法将该数值更新到 `Chart` 控件中。 下面是示例代码: ```csharp using System; using System.Threading; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; namespace ChartThreadDemo { public partial class Form1 : Form { private Random random = new Random(); public Form1() { InitializeComponent(); // 启动新线程 Thread thread = new Thread(new ThreadStart(UpdateChart)); thread.Start(); } private void UpdateChart() { while (true) { // 随机生成一个数值 int value = random.Next(100); // 将数值添加到 Chart 控件中 chart1.Invoke(new Action(() => { chart1.Series[0].Points.AddY(value); chart1.ChartAreas[0].AxisX.ScaleView.Scroll(ChartScrollStyle.Last); })); // 等待一段时间 Thread.Sleep(1000); } } } } ``` 上述代码中,`UpdateChart` 方法是线程的入口点,该方法使用 `Random` 类生成一个随机数值,并通过 `Invoke` 方法将数值添加到 `Chart` 控件中。在 `Invoke` 方法中,使用了一个匿名方法来更新 `Chart` 控件,其中 `Series[0]` 表示 Chart 控件中第一个系列的数据,`Points` 属性表示该系列中的数据点,`AddY` 方法可以将一个数值添加到数据点中。`ChartAreas[0].AxisX.ScaleView.Scroll` 方法可以控制 Chart 控件的滚动,将其滚动到最后一个数据点的位置。 需要注意的是,在更新 Chart 控件时,需要使用 `Invoke` 方法跨线程访问控件,否则会抛出线程访问异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值