C#多線程訪問Winform控制項跨線程問題

來源:互聯網
上載者:User

我們在做winform應用的時候,大部分情況下都會碰到使用多線程式控制制介面上控制項資訊的問題,隨之就極有可能出現這個異常:Cross-thread operation not valid:Control 'textBox1' accessed from a thread other than the thread it was created on。

在網上看了一些解決方案,第一個就是在winfrom的load方法裡加入這行:Control.CheckForIllegalCrossThreadCalls =false;(不推薦)

這句代碼就是說在這個類中我們不檢查跨線程的調用是否合法(如果沒有加這句話運行也沒有異常,那麼說明系統以及預設的採用了不檢查的方式)。然而,這種方法不可取。我們查看CheckForIllegalCrossThreadCalls 這個屬性的定義,就會發現它是一個static的,也就是說無論我們在項目的什麼地方修改了這個值,他就會在全域起作用。而且像這種跨線程訪問是否存在異常,我們通常都會去檢查。如果項目中其他人修改了這個屬性,那麼我們的方案就失敗了。
第二個就是所謂的使用delegate和invoke來從其他線程中控制控制項資訊,但是我不這麼認為,感覺這種方法的要點在於Control.Invoke Method,而感覺使用delegate和invoke會會誤導別人,好像使用一個delegate然後invoke就好了,其實delegate只不過是起輔助作用而已,真正起作用的還是Control.Invoke Method,看下面的code:

 

public partial class Form1 : Form    {        private delegate void FlushClient();//代理        public Form1()        {            InitializeComponent();        }        private void Form1_Load(object sender, EventArgs e)        {            Thread thread = new Thread(CrossThreadFlush);            thread.IsBackground=true;            thread.Start();        }        private void CrossThreadFlush()        {            //將代理綁定到方法             FlushClient fc = new FlushClient(ThreadFuntion);            this.BeginInvoke(fc);       //重點其實是在這裡,前面定義的delegate什麼的都是為了讓建立這個Control的線程去調用這個ThreadFuntion 方法         
} private void ThreadFuntion() { while (true) { this.textBox1.Text = DateTime.Now.ToString(); Thread.Sleep(1000); } } }

說到Control.Invoke Method,就不得不提下Control.InvokeRequired Property,藉助下面的code來看下這個property:

 f (this.InvokeRequired)            {                this.BeginInvoke(new MethodInvoker(LoadGlobalImage));                return;            }

c#中禁止跨線程直接存取控制項,InvokeRequired是為瞭解決這個問題而產生的當一個控制項的InvokeRequired屬性值為真時,說明有一個建立它以外的線程想訪問它。此時它將會在內部調用new MethodInvoker(LoadGlobalImage)來完成下面的步驟,這個做法保證了控制項的安全,你可以這樣理解,有人想找你借錢,他可以直接在你的錢包中拿,這樣太不安全,因此必須讓別人先要告訴你,你再從自己的錢包把錢拿出來借給別人,這樣就安全了。

這樣就可以很好的理解上面那個winform程式中 this.BeginInvoke(fc);這行code了,這個執行後其實也就是主線程在調用fc中綁定的方法ThreadFuntion()了,這種方式其實相當於把這個新開的線程“注入”到了主控制線程中,它取得了主線程的控制。只要這個線程不返回,那麼主線程將永遠都無法響應。就算新開的線程中不使用無限迴圈,使可以返回了。這種方式的使用多線程也失去了它本來的意義。

下面就要用到InvokeRequired這個propety

public partial class Form1 : Form    {        private delegate void FlushClient();//代理        public Form1()        {            InitializeComponent();        }        private void Form1_Load(object sender, EventArgs e)        {            Thread thread = new Thread(CrossThreadFlush);            thread.IsBackground = true;            thread.Start();        }        private void CrossThreadFlush()        {            while (true)            {                //將sleep和無限迴圈放在等待非同步外面                Thread.Sleep(1000);                ThreadFunction();            }        }        private void ThreadFunction()        {            if (this.textBox1.InvokeRequired)//等待非同步            {                FlushClient fc = new FlushClient(ThreadFunction);                this.Invoke(fc);//通過代理調用重新整理方法            }            else            {                this.textBox1.Text = DateTime.Now.ToString();            }        }    }

運行上述代碼,我們可以看到問題已經被解決了,通過等待非同步,我們就不會總是持有主線程的控制,這樣就可以在不發生跨線程調用異常的情況下完成多線程對winform多線程式控制件的控制了。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.