分享

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

 长江黄鹤 2024-03-12 发布于湖北

前言

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

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

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

2、刷新UI控件

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

控件:pictureBox1

  1. public delegate void DeleMyDelegate();//定义委托
  2. DeleMyDelegate deleMyDelegate;//声明委托
  3. public void DeleMy()//定义信息函数
  4. {
  5. pictureBox1.Refresh();
  6. }
  7. public void Pic_Show()
  8. {
  9. deleMyDelegate = new DeleMyDelegate(DeleMy);//绑定委托
  10. this.pictureBox1.Invoke(deleMyDelegate);
  11. }
  12. private void button1_Click(object sender, EventArgs e)
  13. {
  14. Thread myThread = new Thread(Pic_Show);
  15. myThread.Start();
  16. }

控件:richTextBox1

  1. Thread myThread;
  2. public delegate void MyDelegateUI(); //定义委托类型
  3. MyDelegateUI myDelegateUI; //声明委托对象
  4. public Form1()
  5. {
  6. InitializeComponent();
  7. myThread = new Thread(doWork);
  8. myDelegateUI = new MyDelegateUI(initAll);//绑定委托
  9. }
  10. private void initAll() //信息处理函数定义
  11. {
  12. richTextBox1.AppendText("TEST line \r");
  13. }
  14. private void doWork()
  15. {
  16. for (int i = 0; i < 10; i++)
  17. {
  18. Thread.Sleep(100);
  19. this.Invoke(myDelegateUI); //richTextBox1.AppendText("TEST line \r");
  20. Application.DoEvents();
  21. }
  22. }
  23. private void button1_Click(object sender, EventArgs e)
  24. {
  25. myThread.Start();
  26. }

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

(1)工作线程类

  1. public class Work
  2. {
  3. private volatile static Work instanceWork; // 单例
  4. public delegate void InvokeListBox(int i);
  5. public InvokeListBox invokeOthers;
  6. /// <summary>
  7. /// 构造函数
  8. /// </summary>
  9. public Work()
  10. {
  11. }
  12. /// <summary>
  13. /// 对外接口,获取单例
  14. /// </summary>
  15. /// <returns></returns>
  16. public static Work GetInstance()
  17. {
  18. if (null == instanceWork)
  19. {
  20. instanceWork = new Work();
  21. }
  22. return instanceWork;
  23. }
  24. /// <summary>
  25. /// 业务函数,在工作过程中将状态传给主界面
  26. /// </summary>
  27. public void DoSomething()
  28. {
  29. for (int i = 0; i < 20; i++)
  30. {
  31. Thread.Sleep(1000);
  32. invokeOthers(i);
  33. }
  34. }
  35. }

(2)主界面布局及代码

  1. private delegate void InvokeListBox(string strCon); // 刷新ListBox的委托。
  2. private InvokeListBox invokeListBox;
  3. private Work wk; //工作线程对象
  4. public Form1()
  5. {
  6. InitializeComponent();
  7. wk = Work.GetInstance(); //单例模式初始化工作线程对象
  8. wk.invokeOthers = new Work.InvokeListBox(ReciveData); // 绑定,接收工作线程过来的数据
  9. invokeListBox = new InvokeListBox(RefrushListBox); // 绑定,刷新界面ListBox控件
  10. }
  11. private void button1_Click(object sender, EventArgs e)
  12. {
  13. Thread th = new Thread(new ThreadStart(wk.DoSomething));
  14. th.Start();
  15. }
  16. /// <summary>
  17. /// 接收工作线程过来的数据,更新界面
  18. /// </summary>
  19. /// <param name="i"></param>
  20. public void ReciveData(int i)
  21. {
  22. string strConten = i.ToString() + " 更新";
  23. if (this.listBox1.InvokeRequired)
  24. {
  25. this.listBox1.Invoke(invokeListBox, new object[] { strConten });
  26. }
  27. }
  28. /// <summary>
  29. /// 具体刷新界面函数
  30. /// </summary>
  31. /// <param name="_str"></param>
  32. public void RefrushListBox(string _str)
  33. {
  34. this.listBox1.Items.Add(_str);
  35. }

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

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多