• C# Winform 多线程更新界面UI控件,解决界面卡顿问题(转)


    前言

            多线程刷新界面主要用到多线程,委托,线程安全、事件等一系列高难度的C#操作。

    1、使用timer控件对要刷新的控件进行定时刷新

            对刷新频率要求不高的时候,可以使用该方法。

    2、刷新UI控件

            在开发软件时经常会需要更新界面上的某个控件来显示相关的信息,为了让程序执行中不出现界面卡死的现像,最好的方法就是“多线程+委托”来解决。

    控件:pictureBox1

            public delegate void DeleMyDelegate();//定义委托
            DeleMyDelegate deleMyDelegate;//声明委托
            public void DeleMy()//定义信息函数
            {
                pictureBox1.Refresh();
            }
            public void Pic_Show()
            {
                deleMyDelegate = new DeleMyDelegate(DeleMy);//绑定委托
                this.pictureBox1.Invoke(deleMyDelegate);
            }
            
            private void button1_Click(object sender, EventArgs e)
            {
                Thread myThread = new Thread(Pic_Show);
                myThread.Start();
            }

    控件:richTextBox1

            Thread myThread;
            public delegate void MyDelegateUI(); //定义委托类型
            MyDelegateUI myDelegateUI; //声明委托对象
            public Form1()
            {
                InitializeComponent();
    
                myThread = new Thread(doWork);
                myDelegateUI = new MyDelegateUI(initAll);//绑定委托
            }
    
            private void initAll() //信息处理函数定义
            {
                richTextBox1.AppendText("TEST line 
    ");
            }
    
            private void doWork()
            {
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(100);
                    this.Invoke(myDelegateUI); //richTextBox1.AppendText("TEST line 
    ");
                    Application.DoEvents();
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                myThread.Start();
            }

    3、工作线程中刷新主界面控件状态

    (1)工作线程类

        public class Work
        {
            private volatile static Work instanceWork;    // 单例
    
            public delegate void InvokeListBox(int i);
            public InvokeListBox invokeOthers;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            public Work()
            {
    
            }
    
            /// <summary>
            /// 对外接口,获取单例
            /// </summary>
            /// <returns></returns>
            public static Work GetInstance()
            {
                if (null == instanceWork)
                {
                    instanceWork = new Work();
                }
    
                return instanceWork;
            }
    
            /// <summary>
            /// 业务函数,在工作过程中将状态传给主界面
            /// </summary>
            public void DoSomething()
            {
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(1000);
                    invokeOthers(i);
                }
            }
    
        }

    (2)主界面布局及代码

            private delegate void InvokeListBox(string strCon);    // 刷新ListBox的委托。
            private InvokeListBox invokeListBox;
    
            private Work wk;    //工作线程对象
    
            public Form1()
            {
                InitializeComponent();
    
                wk = Work.GetInstance();    //单例模式初始化工作线程对象
                wk.invokeOthers = new Work.InvokeListBox(ReciveData);    // 绑定,接收工作线程过来的数据
                invokeListBox = new InvokeListBox(RefrushListBox);       // 绑定,刷新界面ListBox控件
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Thread th = new Thread(new ThreadStart(wk.DoSomething));
                th.Start();
            }
    
            /// <summary>
            /// 接收工作线程过来的数据,更新界面
            /// </summary>
            /// <param name="i"></param>
            public void ReciveData(int i)
            {
                string strConten = i.ToString() + "  更新";
    
                if (this.listBox1.InvokeRequired)
                {
                    this.listBox1.Invoke(invokeListBox, new object[] { strConten });
                }
            }
    
            /// <summary>
            /// 具体刷新界面函数
            /// </summary>
            /// <param name="_str"></param>
            public void RefrushListBox(string _str)
            {
                this.listBox1.Items.Add(_str);
            }

    (3)说明

            本例子中有两个委托:1、Work.cs中的委托变量 ivokeOthers,作用是将信息传递给给主界面对应的函数:ReceiveData()。2、Form_MainUI.cs中的委托变量 invokeListBox,作用是刷新界面控件ListBox_state的内容。点击“开始工作”按钮后,工作线程启动,调用Work.cs中DoSomeThing()函数。由于Form_MainUI.cs中的函数ReceiveData()函数绑定了Work.cs中的委托ivokeOthers,所以当Work.cs中DoSomeThing被调用时ivokeOthers会把变量i传递给ReceiveData()。ReceiveData()接收到数据后,通过Invoke调用刷函数RefrushListBox()修改主界面ListBox_State的内容。

    (4)总结

            1)不要惧怕委托、事件的复杂的概念,动手操作练习一下,就简单的把它们当做传递消息的载体。

            2)在工作线程中修改主界面其它控件的内容、状态、图片等操作类似,可以自己动手试试。

            3)本小结在实现刷新主界面控件的时候使用了单例模式,不使用单例模式也完全可以实现,加上单例是为了让调用更加方便,在大项目开发中就会体现其优势。

    https://blog.csdn.net/kingshown_WZ/article/details/89322499?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

  • 相关阅读:
    Ajax的技术与原理探讨
    Ajax技术与原理
    AJAX原理
    vue中ref的一些常见作用
    表的连接查询
    mysql使其支持插入中文数据的办法
    16 散列表-基于除余留数法与线性探测法的实现
    win10上Tensorflow的安装教程
    哨兵/sentinel:在算法设计中的应用
    快速选择算法/Select 寻找第k大的数
  • 原文地址:https://www.cnblogs.com/xihong2014/p/13924059.html
Copyright © 2020-2023  润新知