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

C#--耗时操作实现UI界面实时更新不阻塞(耗时操作解决窗体卡顿)

admin
2024年11月27日 18:53 本文热度 628

前言

C#实现窗体加载进度条或者百分比实时显示耗时操作的进度,方法有很多。但是经过我的学习、查找与实际应用,发现Task配合MethodInvoker最为高效便捷。下面我就来结合代码讲一下要注意的问题。


基础知识

C#在winform上进行耗时操作往往会放置progressbar,问题是在UI线程上进行耗时操作就会导致UI线程阻塞,界面就会卡顿。所以势必要另开一个线程进行耗时操作,之后将耗时操作的过程实时反馈给UI线程即可,可问题是新开的线程向UI线程传递数据的时候,就会出现经典报错:

InvalidOperationException,并提示消息:“从不是创建控件的线程访问它。

这是因为NET原则上禁止跨线程访问。因为这样可能造成错误的发生,有一种简单粗暴的方法是禁止编译器对跨线程访问作检查,Control.CheckForIllegalCrossThreadCalls = false;可以实现访问,但是什么时候出错不敢保证。

Task

Task是一个升级版本的Thread的类,它非常的灵活,支持取消、阻塞等待、合并、多个Task协同操作......。总之使用Task编码高效易懂,你基本不用去研究Thread与ThreadPool了,虽然本质上还是这个。我个人理解Task就是对Thread的再次封装。

MethodInvoker

MethodInvoker 是位于System.Windows.Forms下的元数据,表示一个委托,该委托可以执行托管代码中声明为void且不接受任何参数的任何方法。在对控件的 invoke 方法进行调用时或需要一个简单委托又不想自己定义时可以使用该委托。 我是这样理解的,在新线程中使用 MethodInvoker 委托执行耗时操作, 其实相当于是在主线程中执行的,这样就避免了跨线程访问控件。


示例代码

private void button1_Click(object sender, EventArgs e)

{

    progressBar1.Visible = true;

    Task task = new Task(() =>

    {

        int i = 0;

        while (++i < 100)

        {

            Thread.Sleep(10);//模拟耗时操作

            MethodInvoker mi = new MethodInvoker(() =>

            {

                progressBar1.Value = i;

                this.label1.Text = i.ToString();

            });

            this.BeginInvoke(mi);

        }

    });

    task.Start();

    task.ContinueWith(t => {

        progressBar1.Visible = false;

    },TaskScheduler.FromCurrentSynchronizationContext());

}

线程的延续采用ContinueWith解决

BeginInvoke解决界面的刷新问题

TaskScheduler.FromCurrentSynchronizationContext() 解决跨线程访问报错

private void button2_Click(object sender, EventArgs e)

{

    Task task1 = new Task(() =>

    {

        M1();

        MethodInvoker mi = new MethodInvoker(() =>

        {

            this.label1.Text = "1";

        });

        this.BeginInvoke(mi);

        M2();

        mi = new MethodInvoker(() =>

        {

            this.label1.Text = "2";

        });

        this.BeginInvoke(mi);

    });

    task1.Start();

    this.label1.Text="主线程开始运行!" ;

}

private void M1()

{

    Thread.Sleep(2000);

}

private void M2()

{

    Thread.Sleep(1000);

}

button2的方式可以在task线程中按顺序执行耗时操作。


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