首页 > 代码库 > 多线程、委托、Invoke解决winform界面卡死的问题,并带开关

多线程、委托、Invoke解决winform界面卡死的问题,并带开关

一、知识点介绍
1,更新控件的内容,应该调用控件的Invoke方法。
Invoke指: 在拥有控件的基础窗口句柄的线程上,用指定的参数列表执行指定委托。该方法接收一个委托类型和委托的参数,因此需要定义委托类型变量,然后传递给Invoke方法。
 
如果其他线程直接调用方法更新控件内容,报错:线程间操作无效: 从不是创建控件“richTextBox1”的线程访问它。
 
2,委托的本质是某一类型的方法,这些方法具有相同的参数和返回类型。
委托类似于C语言中的函数指针,可以指向多个相同类型的函数。
定义委托,只需要在函数返回类型前加上delegate关键词,把函数体大括号{}的内容换成分号即可。比如:
public delegate void DelegateFun(string msg);
DelegateFun就代表了一个函数类型,它接收string参数,返回void。
 
3,开辟一个线程,直接启动,后面通过挂起和唤醒实现暂停功能。
Thread t = new Thread(Run);
t.Start(); // 启动
通过判断线程状态,决定是否唤醒线程。
if (t.ThreadState == ThreadState.Suspended) // 如果被挂起了,就唤醒
{
t.Resume();
}
暂停就挂起线程:
t.Suspend(); // 停止,挂起线程
 
注:也可以定义一个开关,用来控制开始和结束,在开关为false的时候,直接continue,这样表现为暂停输出,但是实际上线程一直在运行。
 
二、界面和代码
技术分享
 

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading;namespace WindowsFormsApplication3{    public partial class Form2 : Form    {        public Form2()        {            InitializeComponent();        }        /// <summary>        /// 因为控件的Invoke方法需要接收委托变量,因此需要定义委托和委托变量        /// 定义一个委托,接收一个参数        /// </summary>        /// <param name="msg"></param>        public delegate void DelegateFun(string msg);        /// <summary>        /// 定义一个委托变量        /// 这个委托变量,需要初始化指定具体的方法;然后传递给控件的Invoke方法调用。        /// </summary>        public DelegateFun Fun1;        /// <summary>        /// 定义一个线程,处理数据,并更新界面        /// </summary>        private Thread t = null;        // 开始按钮        private void button1_Click(object sender, EventArgs e)        {            this.Invoke(Fun1, "开始...");                                // 增加判断,避免每次单击都开辟一个线程            if (t == null)            {                t = new Thread(Run);                t.Start();               }            if (t.ThreadState == ThreadState.Suspended) // 如果被挂起了,就唤醒            {                t.Resume();            }                       }        // 结束执行        private void button2_Click(object sender, EventArgs e)        {                       t.Suspend(); // 停止,挂起线程            this.Invoke(Fun1, "...停止");        }                // 具体做事情的方法        public void Run()        {            //...... 处理一些事情,然后输出日志            int i = 0;                       while (true)            {                               i++;                // this指Form2                //Invoke指: 在拥有控件的基础窗口句柄的线程上,用指定的参数列表执行指定委托。                //Invoke的参数是一个委托类型,因此必须定义委托变量                 this.Invoke(Fun1, i.ToString());                           }        }        //在form初始化的时候,给委托变量赋值具体的方法        private void Form2_Load(object sender, EventArgs e)        {            //给委托变量初始化具体的执行方法            Fun1 = Print;        }        // 输出日志的方法        public void Print(string msg)        {            // 新开辟的线程,不能直接调用这个方法。原因是控件只能由创建它的线程调用。            // 其他线程调用提示错误: 线程间操作无效: 从不是创建控件“richTextBox1”的线程访问它。            this.richTextBox1.AppendText(msg + "\r\n");            this.richTextBox1.ScrollToCaret();        }    }}

 

 

 
三、参考文章
1, C#多线程解决界面卡死问题的完美解决方案,BeginInvoke而不是委托delegate
http://www.sufeinet.com/thread-3556-1-1.html

多线程、委托、Invoke解决winform界面卡死的问题,并带开关