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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM