多線程耗時操作及界面更新

要提高界面的響應特性,最好的辦法莫過於使用多線程,並把呈現界面的線程獨立出來。以前只有使用C++才能實現的多線程功能,現在在.Net框架下,所有的語言(包括VB)都可以使用了。不過,使用多線程比使用單一線程要麻煩得多,比如線程之間的同步問題,做得不好很容易出錯,而有的時候這種錯誤要開發人員花上幾個星期的時間才能找到。在Windows Form軟件中使用多線程更是有一些限制。


0. 在主程序執行一些長時間的耗時操作時候,(比如很多次的循環for(,,), 或者Thread.Sleep(xxx)), UI會沒有反應。(因爲窗口處理事件是按照消息隊列中的順序來的,沒有處理到的就會帶在隊列裏面,其中可能包括界面重繪即響應事件)。

1. 需要提高界面響應,可以使用新的線程來做一些耗時的操作,同時界面保持響應。

2. 耗時操作完成後,使用Control.Invoke/BeginInvoke來更新界面,有同步和異步兩個方式,InvokeRequired是用來判斷是否需要線程切換(Invoke實際上是把代碼切換到主線程,也就是界面線程上面去執行)

3.搞清楚代碼到底是在哪個線程上面執行。在new Thread()裏面的代碼都是在另外的線程上執行

1.Form1.cs

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 UpdateUITest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string mnem = this.textBox1.Text.Trim();
            //string price = GetPriceUsingNewThread(mnem);
            GetPriceUsingNewThread(mnem);
        }

        private void GetPriceUsingNewThread(string mnem)
        {
            string price = ServiceProvider.GetPrice2(mnem);
        
            this.textBox2.Text = price;
        }

        private void GetPriceUsingNewThread2(string mnem)
        {
            string price = string.Empty;

            new Thread(()=>
            {
                price = ServiceProvider.GetPrice(mnem);
                if (this.InvokeRequired)
                {
                    this.Invoke(new Action(() =>
                        {
                            this.textBox2.Text = price;
                        }));
                }
                else
                {
                    this.textBox2.Text = price;
                }
            }).Start();
        }

        private void GetPriceUsingNewThreadInLamda(string mnem)
        {
            string price = string.Empty;
            bool hasGotValue = false;

            new Thread(()=>
            {
                price = ServiceProvider.GetPrice(mnem);
                hasGotValue = true;
            }).Start();

            while (!hasGotValue)
            {
                Application.DoEvents();
            }

            this.textBox2.Text = price;
        }
    }
}



2. ServiceProvider.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace UpdateUITest
{
    class ServiceProvider
    {
        public static string GetPrice(string mnem)
        {
            string resultPrice;

            if (mnem.ToUpper() == "IBM")
            {
                resultPrice = "10.00";
            }
            else
            {
                resultPrice = "20.00";
            }

            System.Threading.Thread.Sleep(9000);

            return resultPrice;
        }

        public static string GetPrice2(string mnem)
        {
            string resultPrice;

            if (mnem.ToUpper() == "IBM")
            {
                resultPrice = "10.00";
            }
            else
            {
                resultPrice = "20.00";
            }

            //If you are doing something which would last a long time
            //,please give main thread(UI thread) a chance to update itself every other few miliseconds.
            for (int i = 0; i < 5000; i++)
            {
                Application.DoEvents();
                System.Threading.Thread.Sleep(2);
            }

            return resultPrice;
        }
    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章