blog.Toby

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            130 隨筆 :: 2 文章 :: 150 評論 :: 0 Trackbacks

          Vs 2003用多了,裝了VS 2005就有點(diǎn)用不習(xí)慣了,以前在2003里面不會因?yàn)樵诰€程里面對其它線程中的控件進(jìn)行操作而報(bào)錯,到了2005這個就變成一個異常了,不過這也是為了線程之間的安全性,所以只能找新的方法來實(shí)現(xiàn)原來的跨線程操作了。
             在講解如何進(jìn)行跨線程操作前,我抄一段摘自網(wǎng)上關(guān)于VS2005進(jìn)行這一改動的好處的說法:
              由于Windows窗體控件本質(zhì)上不是線程安全的。因此如果有兩個或多個線程適度操作某一控件的狀態(tài)(set value),則可能會迫使該控件進(jìn)入一種不一致的狀態(tài)。還可能出現(xiàn)其他與線程相關(guān)的bug,包括爭用和死鎖的情況。所以VS2005這一改動便可以增強(qiáng)線程安全性。
             我想大家更關(guān)心的是如何解決這個問題,如何才能操作其它線程中的控件而不引發(fā)異常,接下來我們就來探討下這個問題:

           

          第一種方法:

          這種方法我沒用過,因?yàn)榇蠹彝扑]不要使用,所以我沒去實(shí)驗(yàn)過,具體方法如下(摘自網(wǎng)上):
              設(shè)置System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls  =  false;(winform.下)如果在你的程序初始化的時候設(shè)置了這個屬性,而且在你的控件中使用的都是微軟Framework類庫中的控件的話,系統(tǒng)就不會再拋出你上面所說的這個錯誤了。當(dāng)然這只是為了將VS2003的代碼轉(zhuǎn)換到VS2005下所使用的一種常見的方法。不建議采用;

           

          第二種方法,也是我今天主要要講的就是利用delegate和invoke這個方法:

          思路:把想對另一線程中的控件實(shí)施的操作放到一個函數(shù)中,然后使用delegate代理那個函數(shù),并且在那個函數(shù)中加入一個判斷,用InvokeRequired來判斷調(diào)用這個函數(shù)的線程是否和控件線程在同一線程中,如果是則直接執(zhí)行對控件的操作,否則利用控件的Invoke或BeginInvoke方法來執(zhí)行這個代理。

          在繼續(xù)講解下去之前我們先來看一下這里提到的幾個方法(如果對以下兩個東東已經(jīng)了解了就可以跳過)

           

          首先是Invoke

          Invoke的中文解釋是喚醒,它有兩種參數(shù)類型我們這里只講一種即(Delegate, Object[])

          Delegate就是前面提到的那個代理,而Object[]則是用來存放Delegate所代理函數(shù)的參數(shù)

          MSDN上關(guān)于INVOKE方法有如下說明:在擁有控件的基礎(chǔ)窗口句柄的線程上,用指定的參數(shù)列表執(zhí)行指定委托。

          用通俗的話講就是利用控件的INVOKE方法,使該控件所在的線程執(zhí)行這個代理,也就是執(zhí)行我們想對控件進(jìn)行的操作,相當(dāng)于喚醒了這個操作;

          其次是控件的InvokeRequired這個屬性(個人翻譯為’喚醒請求’):

          MSDN上關(guān)于它的解釋是獲取一個值,該值指示調(diào)用方在對控件進(jìn)行方法調(diào)用時是否必須調(diào)用Invoke方法,因?yàn)檎{(diào)用方位于創(chuàng)建控件所在的線程以外的線程中。

          有通俗的話講就是返回一個值,如果與控件屬于同一個線程,則不需要進(jìn)行喚醒的請求,也就是返回值為False,否則則需要進(jìn)行喚醒的請求,返回為true

          總感覺MSDN上的翻譯讓人無法一看就明白,可能是自己智力不夠吧~~

           

          最后就是我們的具體程序了:
                 delegate void aa(string  s);//創(chuàng)建一個代理

                 private void  pri(string t)//這個就是我們的函數(shù),我們把要對控件進(jìn)行的操作放在這里

                 {

                     if  (!richTextBox1.InvokeRequired)//判斷是否需要進(jìn)行喚醒的請求,如果控件與主線程在一個線程內(nèi),可以寫成if(!InvokeRequired)

                     {

                         MessageBox.Show("同一線程內(nèi)");

                         richTextBox1.Text =t;

                     }

                     else

                     {

                         MessageBox.Show("不是同一個線程");

                         aa a1 =new aa(pri);

                         Invoke(a1,new object []{t});//執(zhí)行喚醒操作

                     }

                 }

                 private void  Form1_Load(object sender, System.EventArgse)

                 {

                     Thread  newthread = new Thread(new ThreadStart(ttread));

                     newthread.Start();

                 }

                 void  ttread()

                 {

                     pri("sdfs");

                 }

          執(zhí)行結(jié)果先調(diào)出一個提示框顯示“不是同一個線程”,然后跳出提示框顯示“同一線程內(nèi)”,然后richTextBox1中的text值為sdfs;這樣便完成了對其它線程中的控件進(jìn)行操作。

          http://cnedu.blog.ytedu.cn/archives/2008/20082892324.html

          posted on 2008-07-07 14:22 渠上月 閱讀(4099) 評論(0)  編輯  收藏 所屬分類: VS 2005
          主站蜘蛛池模板: 克拉玛依市| 海丰县| 宣化县| 郧西县| 恩施市| 吉隆县| 衡阳县| 拉孜县| 唐山市| 兴化市| 桓台县| 曲松县| 天水市| 盐山县| 洛南县| 读书| 岳普湖县| 灌南县| 盘山县| 格尔木市| 吴旗县| 平塘县| 新野县| 望都县| 贵定县| 武胜县| 大庆市| 新源县| 宜都市| 射阳县| 黑水县| 永年县| 红原县| 旅游| 社旗县| 大竹县| 靖边县| 平泉县| 同江市| 克什克腾旗| 博野县|