多线程、委托、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

时间: 2024-10-06 00:07:14

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

【C#】多线程解决UI界面卡死的问题

一个经典的例子: http://www.cnblogs.com/wangchuang/p/4485797.html 问题: 都说Invoke是同步的,BeginInvoke是异步的,但为何用BeginInvoke做耗时操作依然会卡死UI? http://www.cnblogs.com/blosaa/archive/2013/05/30/3107381.html 小结: BeginInvoke的异步是指相对于调用BeginInvoke的线程异步,而不是相对于UI线程异步.所以在UI线程调用Begi

解决 winform 界面对不齐

最近做了一个winform的程序,本机上界面对得很齐,到一到客户的机器上就惨不忍睹,一番研究后搞定: 1. AutoScaleMode = None 2. BackgroundImageLayout = None 疯吻IT

解决WinForm界面闪烁问题

前言 之前將.net 1.1 Windows Form程式升級到.net 4.0,結果在開畫面時,閃的非常利害!  於是就開始找解決方法. 研究及解決 開始找到了設定DoubleBuffer=true,這個有一點點用,在高檔的機器上面,但是在4年前的NB問題還是一樣,尤其是當畫面物件很多時,感覺是一個一個畫出來! 還是被USER噹~~ 後來找到了「How to fix the flickering in User controls」,照他的方式來做,效能果然是一粒一的好呀! 他的方式是在Form

C# 解决winform界面闪屏问题

1 添加以下代码: // 防止闪屏 protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } }

WPF 解决界面卡死

工作中的项目,CS客户端会通过MQ接收前端设备发送的信息,之前测试的时候,由于测试的数据不大,没有进行压力测试,软件可以正常工作,随着项目现场设备数量的增加,CS客户端从MQ中订阅的数据量不断增加,最终导致,客户端界面卡死.原来的数据流程图如下: 这个数据流程,在数据不大的情况下,是没有什么问题,数据太多,从mq获取数据的流程太长,不管是Json反序列化,还是WPF界面渲染,都是耗时比较大.所以决定将数据流程改为如下所示: 修改后的方案,将原来的一个流程拆分两个流程,左边的流程只负责从mq取数据

WinForm多线程+委托防止界面卡死

1.当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System

WinForm 多线程+委托来防止界面假死

参考: http://www.cnblogs.com/xpvincent/archive/2013/08/19/3268001.html 当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using Sy

winform防止界面卡死的三种方法

在编程过程中经常会遇到耗时操作,这个时候如果不采取一些必要的异步操作,就会导致界面的卡死,这里以winform为例子,介绍三种方法防止界面卡死,对这几个方法稍加修改同样适用于wpf,silverlight等程序 首先给出一个函数模拟耗时操作 1使用委托+QueueUserWorkItem delegate void ChangeInvoke(int num) ; private void ChangeNum(int num) { MessageBox.Show(num.ToString());

winform批量更新数据_长时间的执行会导致界面卡死

原文:winform批量更新数据_长时间的执行会导致界面卡死 前言:使用winform触发一个事件后执行的代码,如果耗时非常长,则会导致窗口界面假死!  本人最近通过winform窗体执行一项:需要批量更新一批数据库的数据的操作的任务时,由于数据量达到百万级别,非常耗时,只能慢慢更新,慢慢执行. 但是,在执行的过程遇到了一个奇葩的问题:窗体在调试状态下,代码可以慢慢循环执行,没出现异常.  但是我单独运行EXE程序时,就必现:程序假死,未响应状态. 后台百度虽然没有找到直接的答案,但是也发现了原