C# Winform 多線程更新界面UI控件,解決界面卡頓問題(轉)


前言

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

1、使用timer控件對要刷新的控件進行定時刷新

        對刷新頻率要求不高的時候,可以使用該方法。

2、刷新UI控件

        在開發軟件時經常會需要更新界面上的某個控件來顯示相關的信息,為了讓程序執行中不出現界面卡死的現像,最好的方法就是“多線程+委托”來解決。

控件:pictureBox1

        public delegate void DeleMyDelegate();//定義委托
        DeleMyDelegate deleMyDelegate;//聲明委托
        public void DeleMy()//定義信息函數
        {
            pictureBox1.Refresh();
        }
        public void Pic_Show()
        {
            deleMyDelegate = new DeleMyDelegate(DeleMy);//綁定委托
            this.pictureBox1.Invoke(deleMyDelegate);
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            Thread myThread = new Thread(Pic_Show);
            myThread.Start();
        }

控件:richTextBox1

        Thread myThread;
        public delegate void MyDelegateUI(); //定義委托類型
        MyDelegateUI myDelegateUI; //聲明委托對象
        public Form1()
        {
            InitializeComponent();

            myThread = new Thread(doWork);
            myDelegateUI = new MyDelegateUI(initAll);//綁定委托
        }

        private void initAll() //信息處理函數定義
        {
            richTextBox1.AppendText("TEST line \r");
        }

        private void doWork()
        {
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                this.Invoke(myDelegateUI); //richTextBox1.AppendText("TEST line \r");
                Application.DoEvents();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            myThread.Start();
        }

3、工作線程中刷新主界面控件狀態

(1)工作線程類

    public class Work
    {
        private volatile static Work instanceWork;    // 單例

        public delegate void InvokeListBox(int i);
        public InvokeListBox invokeOthers;

        /// <summary>
        /// 構造函數
        /// </summary>
        public Work()
        {

        }

        /// <summary>
        /// 對外接口,獲取單例
        /// </summary>
        /// <returns></returns>
        public static Work GetInstance()
        {
            if (null == instanceWork)
            {
                instanceWork = new Work();
            }

            return instanceWork;
        }

        /// <summary>
        /// 業務函數,在工作過程中將狀態傳給主界面
        /// </summary>
        public void DoSomething()
        {
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(1000);
                invokeOthers(i);
            }
        }

    }

(2)主界面布局及代碼

        private delegate void InvokeListBox(string strCon);    // 刷新ListBox的委托。
        private InvokeListBox invokeListBox;

        private Work wk;    //工作線程對象

        public Form1()
        {
            InitializeComponent();

            wk = Work.GetInstance();    //單例模式初始化工作線程對象
            wk.invokeOthers = new Work.InvokeListBox(ReciveData);    // 綁定,接收工作線程過來的數據
            invokeListBox = new InvokeListBox(RefrushListBox);       // 綁定,刷新界面ListBox控件
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(new ThreadStart(wk.DoSomething));
            th.Start();
        }

        /// <summary>
        /// 接收工作線程過來的數據,更新界面
        /// </summary>
        /// <param name="i"></param>
        public void ReciveData(int i)
        {
            string strConten = i.ToString() + "  更新";

            if (this.listBox1.InvokeRequired)
            {
                this.listBox1.Invoke(invokeListBox, new object[] { strConten });
            }
        }

        /// <summary>
        /// 具體刷新界面函數
        /// </summary>
        /// <param name="_str"></param>
        public void RefrushListBox(string _str)
        {
            this.listBox1.Items.Add(_str);
        }

(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)本小結在實現刷新主界面控件的時候使用了單例模式,不使用單例模式也完全可以實現,加上單例是為了讓調用更加方便,在大項目開發中就會體現其優勢。

https://blog.csdn.net/kingshown_WZ/article/details/89322499?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param


免責聲明!

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



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