WinForm中新開一個線程操做 窗體上的控件(跨線程操做控件)

最近在作一個winform的小軟件(搶票的...)。登陸窗體要從遠程web頁面獲取一些數據,爲了避免阻塞登陸窗體的顯示,開了一個線程去加載數據遠程的數據,會報一個錯誤"線程間操做無效: 從不是建立控件「lbl_loading_msg」的線程訪問它。"百度一下,原來從.net framework 2.0開始,爲了安全,不容許跨線程操做控件。解決辦法以下:
一、聲明一個擁有委託類型的方法,做爲代理 操做控件的代碼:web

        /// <summary>
        /// 在線程中操做窗體的控件
        /// </summary>
        /// <param name="action"></param>
        private void OpeMainFormControl(Action action)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(action); //返回主線程(建立控件的線程)
            }
            else
            {
                action();
            }
        }

二、而後在線程中,只要是對控件的操做都委託給上面的方法執行,無論是讀取仍是賦值:安全

            Thread t = new Thread(new ThreadStart(delegate()
            {
                //執行一段費時的代碼
                //......
                //線程中操做 控件,委託給invoker
                OpeMainFormControl(delegate()
                {
                    this.lbl_loading_msg.Visible = false; //隱藏驗證碼加載中...的提示
                    this.toolStripStatusLabel1.Text = ""; //清空狀態欄
                    this.btnlogin.Enabled = true;    //啓用登陸按鈕
                });
            }));
            t.Start(); //啓動線程

上面代碼須要注意的是:僅對控件操做的代碼委託給this.invoker。上面委託操做的方法中的this是窗體對象,也就是建立控件的線程,this.invoker(action)就是將代碼交給它來執行。這樣就操做控件的代碼就交給了建立控件的線程來執行了。咱們不要將費時操做的代碼也交給this.invoker來執行,否則就失去了線程的意義了(至關於沒有開線程)。this.inoker又回到了主線程,會產生阻塞!下面代碼會阻塞:ui

                //將費時的代碼也委託給 主線程(建立控件的線程)來執行,會阻塞窗體
                OpeMainFormControl(delegate()
                {
                //執行一段費時的代碼
                //......
                //線程中操做 控件,委託給invoker
                
                    this.lbl_loading_msg.Visible = false; //隱藏驗證碼加載中...的提示
                    this.toolStripStatusLabel1.Text = ""; //清空狀態欄
                    this.btnlogin.Enabled = true;    //啓用登陸按鈕
                });

還有一點:若是對控件的操做代碼沒有委託給建立它的線程來執行(好比實例化另一個窗口,show出來),它的一些設置會不起做用,好比:窗體初始顯示位置等...this

相關文章
相關標籤/搜索