多線程下訪問控件的方式(您必定會用到,附源碼啦!)

前言

     在不少狀況下,咱們都會使用到多線程,在使用多線程的時候,咱們不少時候又會去訪問控件,這裏面就會出現不少問題!!!我以一個最多見的,咱們常常會用到的例子來說講,在提升本身水平的同時,但願能給你們帶來一些方便,有不對的地方還請留言告知,以便及時更正本身的錯誤思想,先謝謝啦!html

一、多線程使用

    有時候在執行一段程序時會耗時比較長,這時候會發現,咱們的窗體就拖不動了,就像卡死了,但那段耗時程序執行完以後,就恢復OK了,這就是咱們常說的程序假死!代碼以下:web

        private void btnCalculate_Click(object sender, EventArgs e)
        {
            Calculate();
        }
        private void Calculate()
        {
            for (int i = 0; i < 500; i++)
            {
                Thread.Sleep(5);
            }
        }
View Code

 這時候使用多線程就很容易解決程序假死問題,修改代碼以下:數組

        private void btnCalculate_Click(object sender, EventArgs e)
        {
            Thread mythread = new Thread(Calculate);
            mythread.IsBackground = true;        //設置為後臺線程,程式關閉後進程也關閉,若是不設置true,則程式關閉,此線程還在內存,不會關閉
            mythread.Start();
        }
        private void Calculate()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            for (int i = 0; i < 500; i++)
            {
                Thread.Sleep(5);
            }
            stopwatch.Stop();
            long lSearchTime = stopwatch.ElapsedMilliseconds;
            MessageBox.Show(lSearchTime.ToString()+"毫秒");
        }
View Code

二、訪問控件方式

以上咱們就解決了程序假死的問題,可需求又來了,我想知道計算的進度,能直觀的感覺到計算多少了,是否是快計算完了,這時候咱們想到了進度條,這時候咱們就加入進度條唄,代碼以下:安全

        private void btnCalculate_Click(object sender, EventArgs e)
        {
            Thread mythread = new Thread(Calculate);
            mythread.IsBackground = true;        //設置為後臺線程,程式關閉後進程也關閉,若是不設置true,則程式關閉,此線程還在內存,不會關閉
            mythread.Start();
        }
        private void Calculate()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            progressBarWay.Maximum = 500;
            for (int i = 0; i < 500; i++)
            {
                Thread.Sleep(5);
                progressBarWay.Value = i;
            }
            stopwatch.Stop();
            long lSearchTime = stopwatch.ElapsedMilliseconds;
            MessageBox.Show(lSearchTime.ToString()+"毫秒");
        }
View Code

以上代碼運行的話程序報錯:報錯信息爲:從不是建立控件控件名稱 的線程訪問它多線程

下面有兩種方式來實現訪問控件:ide

一、不安全方式訪問控件ui

訪問 Windows 窗體控件本質上不是線程安全的。 若是有兩個或多個線程操做某一控件的狀態,則可能會迫使該控件進入一種不一致的狀態。 還可能會出現其餘與線程相關的 Bug,例如爭用狀況和死鎖。 確保以線程安全方式訪問控件很是重要                            ----MSDNthis

   ProgressBar.CheckForIllegalCrossThreadCalls = false;            只須要加入此段代碼就OK,不過不推薦使用spa

二、安全方式訪問控件pwa

下面介紹一下我經過安全方式訪問ProgressBar控件實現的方法

總結爲四步:

定義實現安全訪問控件的委託,第一步:定義帶參數委託Mydelegate,第二步:定義委託要實現的方法SetprogressBar,與委託聲明一致,第三步:聲明並實例化委託並傳入委託要實現的方法,第四步:在實際使用地方調用this.Invoke(mydele, mybar, SelectStatus.myVisible)參數1:聲明的委託名,參數2:委託變量的第一個參數:參數2:委託聲明的第二個參數,具體的代碼以下:

   public partial class SafetyWay : Form
    {
        Mydelegate mydele = null;
        ProgressBar mybar = new ProgressBar();
        public SafetyWay()
        {
            InitializeComponent();
            mydele = new Mydelegate(SetprogressBar);             //第三步:聲明並實例化委託並傳入委託要實現的方法 mydele= new Mydelegate(SetprogressBar)
        }

        private void btnCalculate_Click(object sender, EventArgs e)
        {
            Thread mythread = new Thread(Calculate);
            mythread.IsBackground = true;        //設置為後臺線程,程式關閉後進程也關閉,若是不設置true,則程式關閉,此線程還在內存,不會關閉
            mythread.Start();
        }
        private void Calculate()
        {
            mybar.Visible = true;
            this.Invoke(mydele, mybar, SelectStatus.myVisible);
            Stopwatch stopwatch = Stopwatch.StartNew();
            mybar.Maximum = 500;
            this.Invoke(mydele, mybar, SelectStatus.myMaximum);         //第四步:在實際使用地方調用this.Invoke(mydele, mybar, SelectStatus.myVisible)參數1:聲明的委託名,參數2:委託變量的第一個參數:參數2:委託聲明的第二個參數
            for (int i = 0; i < 500; i++)
            {
                Thread.Sleep(5);
                mybar.Value = i;
                this.Invoke(mydele, mybar, SelectStatus.myValue);
            }
            mybar.Visible = false;
            this.Invoke(mydele, mybar, SelectStatus.myVisible);
            stopwatch.Stop();
            long lSearchTime = stopwatch.ElapsedMilliseconds;
            MessageBox.Show(lSearchTime.ToString() + "毫秒");
        }
        #region 通過委託要實現的方法,設置ProgressBar的屬性值
        private void SetprogressBar(ProgressBar myBar, SelectStatus status)         //第二步:定義委託要實現的方法SetprogressBar,與委託聲明一致
        {
            if (status == SelectStatus.myVisible)
            {
                progressBarWay.Visible = myBar.Visible;
            }
            else if (status == SelectStatus.myValue)
            {
                progressBarWay.Value = myBar.Value;
            }
            else if (status == SelectStatus.myMaximum)
            {
                progressBarWay.Maximum = myBar.Maximum;
            }
        }     
        #endregion
    }
    #region 定義枚舉,記錄要改變的屬性,實際意義如name所示
    public enum SelectStatus
    {
        myVisible,
        myValue,
        myMaximum
    }
    #endregion
    public delegate void Mydelegate(ProgressBar myBar, SelectStatus status); //定義實現安全訪問控件的委託,第一步:定義帶參數委託Mydelegate
View Code

以上的代碼實現方式相對繁瑣,下面給出使用lambda表達式的方式來實現會發現代碼很是簡單,代碼以下:

        private void btnCalculate_Click(object sender, EventArgs e)
        {
            Thread mythread = new Thread(Calculate);
            mythread.IsBackground = true;        //設置為後臺線程,程式關閉後進程也關閉,若是不設置true,則程式關閉,此線程還在內存,不會關閉
            mythread.Start();
        }
        private void Calculate()
        {
            this.Invoke(new Action(() => { progressBarWay.Visible = true; }));
            Stopwatch stopwatch = Stopwatch.StartNew();
            this.Invoke(new Action(() => { progressBarWay.Maximum = 500; }));
            for (int i = 0; i < 500; i++)
            {
                Thread.Sleep(5);
                this.Invoke(new Action(() => { progressBarWay.Value = i; }));
            }
            this.Invoke(new Action(() => { progressBarWay.Visible = false; }));
            stopwatch.Stop();
            long lSearchTime = stopwatch.ElapsedMilliseconds;
            MessageBox.Show(lSearchTime.ToString() + "毫秒");
        }

 上面的代碼樣子好像變化了很多,其實在編譯後編譯器會爲咱們上面省略的一系列代碼再加上去的。

結束語

         以上就是我實際使用中總結的方法,但願對你們有所幫助,附上demo下載地址:http://files.cnblogs.com/beimeng/demo.rar

最後再附上一個獲取ArrayList  數組最大值最小值的方法:

            ArrayList alist = new ArrayList();
            
            alist.Add(5);
            alist.Add(9);
            alist.Add(10);
            alist.Add(3);
            alist.Add(6);
            alist.Add(3);
            int[] myArray = (int[])alist.ToArray(typeof(int)); //將ArrayList轉換為固定類型的Array的方法
            Array.Sort(myArray);                                            //將Array從小到大進行排序
            int Max = myArray[myArray.Length - 1];
            int Min = myArray[0];
View Code
相關文章
相關標籤/搜索