【C#】多线程中,跨线程实现对UI控件更新

问题描述:

“Cross-thread operation not valid :Control ‘listBox1’ accessed from a thread other than the thread it was created on” ,即“线程间操作无效,从不是创建控件“listbox1”的线程访问它。”

原因分析:

UI控件 不是线程安全的,UI控件的设计是仅由创建它们的UI线程进行操作。

解决思路:

解决方法有好几种,这里只介绍 自认为最好的方法:子线程类中建立委托事件,子线程调用事件,具体事件的实现在UI线程中实现。

解决方法示例:

1. 第一步 新建一个消息类

在本类中只包含一个变量:String Message。
实际项目中可以扩展很多变量,比如线程是否即将结束标识、线程已经处理任务的数目等等。

	//消息类,
  public class MessageEventArgs : EventArgs
    {
        public String Message; //消息。
        public MessageEventArgs(string message)
        {
            this.Message = message;
        }
    }

2. 第二步 新建一个子线程类:

 class SubThread
    {
       /// <summary>
       ///  消息委托(题外话,delegate(委托)太形象了,把消息内容委托给 主程序的方法去绑定显示。
       /// </summary>
       /// <param name="sender">委托的发送者,在这里就是SubThread的对象</param>
       /// <param name="e">委托者发送的信息</param>
        public delegate void MessageEventHandler(object sender, MessageEventArgs e);

        //定义事件
        public event MessageEventHandler MessageSend;

        /*
         * 说明:定义事件处理函数,当然这里也可以不用直接在引发事件时调用this.MessageSend(sender, e);
         * 这里的参数要和事件代理的参数一样
         * */
        public void OnMessageSend(object sender, MessageEventArgs e)
        {
            if (MessageSend != null)
                this.MessageSend(sender, e);
        }


        //定义一个线程
        public System.Threading.Thread sendthread;
        
        /// <summary>
        /// 线程的方法
        /// </summary>
        private void UploadTest()
        {
            try
            {
                for (int i = 0; i < 5; i++)
                {
                    System.Threading.Thread.Sleep(1000); //这里让线程睡眠,模拟长时间执行的任务
                    this.OnMessageSend(this, new MessageEventArgs(DateTime.Now.ToString()+" "+(i+1)+"号文件上传成功!"));
                }
            }
            catch
            {
            }
        }

        //线程启动
        public void StartUpload()
        {
            sendthread = new System.Threading.Thread(new System.Threading.ThreadStart(UploadTest));
            sendthread.Start();
        }
      
    }

3. 第三步 新建一个Form

form中新建一个按钮,一个listBox,如下:
在这里插入图片描述
代码:
在主界面类中 的 private void subthread_MessageSend(object sender, MessageEventArgs e)种调用了一个
**Invoke()**的方法,此方法就是可以将 子线程传递过来的message 通过UI线程更新到 listbox1.

 public partial class Form1 : Form
    {

        SubThread subThread;
        
        public Form1()
        {
            InitializeComponent();
            subThread = new SubThread();
            subThread.MessageSend += new SubThread.MessageEventHandler(subthread_MessageSend);
        }
			 //绑定
        public void ListBoxAdd(Object sender,MessageEventArgs msg)
        {
            listBox1.Items.Add(msg.Message);
        }

        public delegate void MessageHandler(Object sender, MessageEventArgs e); //自定义一个委托类型.如果使用系统自带的Action,就无需定义此委托

        private void subthread_MessageSend(object sender, MessageEventArgs e)
        {

            //方式一: 使用自定义的委托,将ListAdd赋值给自定位委托;
            //实例化委托
            MessageHandler handler = new MessageHandler(ListBoxAdd);  //不使用自定义的委托也行,使用Action
            //调用Invoke
            this.Invoke(handler, sender, e); //让主线程调用ListAdd函数,参数为子线程传递的信息

            方式二: 使用系统自带的委托类型Action 
            //Action<object, MessageEventArgs> action = ListBoxAdd;        //使用系统自带的Action委托
            //this.Invoke(action, sender, e);

        }
        private void button1_Click(object sender, EventArgs e)
        {
            
            subThread.StartUpload();
         
        }
    }

运行结果

在这里插入图片描述

相关推荐

  1. 【Android 线】在子线更新UI

    2024-06-06 19:40:03       39 阅读
  2. 线C++更新MYSQL

    2024-06-06 19:40:03       20 阅读
  3. C++ 线

    2024-06-06 19:40:03       26 阅读
  4. C++ 线

    2024-06-06 19:40:03       17 阅读
  5. C#线

    2024-06-06 19:40:03       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 19:40:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 19:40:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 19:40:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 19:40:03       18 阅读

热门阅读

  1. springboot动态切换数据源

    2024-06-06 19:40:03       8 阅读
  2. make 是啥

    2024-06-06 19:40:03       8 阅读
  3. Android基础-工程目录结构说明

    2024-06-06 19:40:03       7 阅读
  4. 呼叫中心系统如何融入信创国产战略?

    2024-06-06 19:40:03       7 阅读
  5. 程序员高效工作(摸鱼)的 10 个方法

    2024-06-06 19:40:03       7 阅读
  6. nn.GRU和nn.GRUCell区别

    2024-06-06 19:40:03       9 阅读
  7. 【MySQL】探索 MySQL 的 GROUP_CONCAT 函数

    2024-06-06 19:40:03       11 阅读