c#多线程耗时操作不卡界面的顺序流程处理方式

By admin at 2021-01-06 • 0人收藏 • 1381人看过

这里新建了method.cs类库, 在类库中需要实时更新数据输出到form1界面中的lable1控件上面 , 我们需要在界面form1中调用此类库, 来执行一个耗时流程.


我们知道在c#里为了不卡界面就需要开多线程 , 多线程里想要更新界面UI控件就需要用到委托 , 看了一些文章发现写的基本千篇一律, 都是在同一个form界面中进行的委托定义和使用, 实际使用中却并不如此, 像我上面的需求, 那么在method类中应该怎么处理才能最简单直接呢?

经过了多次测试, 我发现下面的写法应该是最直观和简单的办法.

我在method中定义一个委托函数, 在form1界面中将这个函数给赋值, 代码如下:


method.cs代码如下:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsFormsApp2
{
    internal class Method
    {
        //定义一个全局委托函数
        public static Action<string> WriteStr;

        //手动停止
        public static bool HandStop { get; set; }
        
        //耗时函数实例
        public static bool demoFunc()
        { 
            var FindOK = false;
            
            var tsk = Task.Run(() => {
                for (int i = 0; i < 100; i++)
                {
                    WriteStr(i.ToString());

                    if (HandStop)
                    {
                        FindOK = false;
                        break;
                    }
                    if (i>40)
                    {
                        FindOK = true;
                        break;
                    }
                    Thread.Sleep(100);
                }
            });
            tsk.Wait();
            return FindOK;
        }
    }
}

 form1.cs界面代码如下:

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 WindowsFormsApp2
{
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            Method.HandStop = false;

            //方式一: 先定义,再使用
            //Action<string> action1 = (str) =>
            //{
            //    Action action = () =>
            //    {
            //        label1.Text = str;
            //    };
            //    this.BeginInvoke(action);
            //};
            //Method.WriteStr = action1;

            //方式二: 直接赋值定义使用
            Method.WriteStr = (str) =>
            {
                Action action = () =>
                {
                    label1.Text = str;
                };
                this.BeginInvoke( action );
            };

            //任务内部会自动调用上面的委托
            var tsk = Task.Run(() =>
            {
                var ret = Method.demoFunc( ) ;
            });
            //等待任务完成
            await tsk;
            Console.WriteLine("ok");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Method.HandStop = true;
        }

        private void button3_Click(object sender, EventArgs e)
        {

            Method.HandStop = true;
        }

    }
}


代码工程如下:

WindowsFormsApp2.zip


开线程无限刷新界面实例:

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 WindowsFormsApp2
{
    
    public partial class Form1 : Form
    {
        //全局定义
        Action<string> loopStr;
        public Form1()
        {
            InitializeComponent();
            //函数初始化
            loopStr = (str) =>
            {
                Action action = () =>
                {
                    label2.Text = str;
                };
                this.BeginInvoke(action);
            };
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Method.HandStop = false;
            Task.Run(() =>
            {
                var i = 0;
                while (!Method.HandStop)
                {
                    //调用
                    loopStr(i.ToString());
                    Thread.Sleep(100);
                    i++;
                }
                Console.WriteLine("loop end");
            });
        }
        
        private void button3_Click(object sender, EventArgs e)
        {

            Method.HandStop = true;
        }
    }
}
using System;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsFormsApp2
{
    internal class Method
    {
        //定义一个全局委托函数
        public static Action<string> WriteStr;

        //手动停止
        public static bool HandStop { get; set; }
        
        //耗时函数实例
        public static bool demoFunc()
        { 
            var FindOK = false;
            
            var tsk = Task.Run(() => {
                for (int i = 0; i < 100; i++)
                {
                    WriteStr(i.ToString());

                    if (HandStop)
                    {
                        FindOK = false;
                        break;
                    }
                    if (i>40)
                    {
                        FindOK = true;
                        break;
                    }
                    Thread.Sleep(100);
                }
            });
            tsk.Wait();
            return FindOK;
        }
    }
}


C#调用dll方法

//第一步,添加dll运行库
using System.Runtime.InteropServices;
//第二步,
[DllImport("Demo.dll", EntryPoint = "demo_init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern UInt16 demo_init();
[DllImport("Demo.dll", EntryPoint = "demo_read_inbit", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern Int32 demo_read_inbit(UInt16 cardno, UInt16 bitno);



3 个回复 | 最后更新于 2024-03-02
2024-02-19   #1
public async void HeadTailClick(Button bt, Action tsk)
{
    var preColor = bt.BackColor;
    bt.BackColor = Color.Chocolate;
    bt.Enabled = false;

    //await Task.Run(tsk).ConfigureAwait(false);
    await Task.Factory.StartNew(tsk, TaskCreationOptions.LongRunning).ConfigureAwait(false);

    bt.Enabled = true;
    bt.BackColor = preColor;
}


private void button12_Click(object sender, EventArgs e)
{
    HeadTailClick((Button)sender, () =>
    {
        var axis = (ushort)GLoableVar.AxisNum.L;
        USBMove.setAxisSpeed(axis, 30000);

        var pos = double.Parse(PicIni.GetKeyValue("镜头位置", "芯片左", USBMove.getPos(axis).ToString()));
        USBMove.pMoveAbs(axis, pos);
        USBMove.waitStop(axis);

        //切换轴
        rb_left.PerformClick();
    });
}

M0KHF`L2]_4[X8M1`G{F78J.png

2024-02-20   #2

回复#1 @admin :

其实用wpf的话,只需要把界面上要显示的控件绑定到要更新的数据上就可以实现同步更新了。

当然,底层其实是用了CommunityToolkiet.MVVM框架的ObservableProperty实现的。

WpfAppDemo.zip

可以参考上述例子,当然如果用OnpropertyChanged事件能更好得实现数据绑定,参考注释部分代码。

2024-03-02   #3

认真学习一下

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...