欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
WPF中Dispatcher的初步探討

  今天要專(zhuān)門(mén)講一下Dispatcher,原因是WPF中經(jīng)常碰到多線(xiàn)程下軟件界面控件的更新問(wèn)題。相信很多初步接觸WPF的界面開(kāi)發(fā)的朋友,為了保持界面不卡,在一個(gè)自己創(chuàng )建的線(xiàn)程中去更新或者讀取一個(gè)控件時(shí)都會(huì )遇到了一個(gè)很奇怪的Exception異常,顯示如下:

    這個(gè)異常是告訴我們,不好意思您非法操作了。

    這個(gè)問(wèn)題我個(gè)人認為估計99.9%的人都碰到過(guò)。因此,很多人覺(jué)得微軟的WPF真不好用,就簡(jiǎn)單更新下界面咋就這么費勁,那怕僅僅是讀取下TexBox的Text屬性就立馬崩潰。個(gè)人也覺(jué)得這是微軟底層架構的問(wèn)題導致使用當中不太方便,但是架構咱們改變不了,只能硬著(zhù)頭皮學(xué)習怎么用。

    相信很多人都也都通過(guò)無(wú)所不能的度娘找到解決辦法了,就是加一段類(lèi)似下面的語(yǔ)句:

this.Dispatcher.Invoke(()=> { // 你的訪(fǎng)問(wèn)空間或者改變控件代碼});

   加了上面的this.Dispatcher.Invoke()就解決了異常問(wèn)題,問(wèn)題解決了,解決的辦法是完全正確無(wú)誤的,但總感覺(jué)硌得慌,干嘛這么費勁? 我也覺(jué)得不直接、可讀性差?。?!但咱們也沒(méi)辦法,因為微軟就是這么任性。

    好了,言歸正傳,繞了這么一圈,我們就需要回過(guò)頭來(lái)看看Dispatcher是個(gè)啥玩意?

    先簡(jiǎn)單說(shuō)幾句啰嗦的話(huà),希望能夠了解,能大概記住是最好的:

    1)官方說(shuō),WPF一般來(lái)說(shuō)啟動(dòng)后會(huì )有兩個(gè)線(xiàn)程,一個(gè)是責呈現,一個(gè)負責UI界面管理。官方對什么是負責呈現和什么是負責UI界面管理簡(jiǎn)單的介紹了下,在此不做贅述。不過(guò)需要記住的就是UI界面管理這個(gè)線(xiàn)程;

    2)負責UI界面管理的線(xiàn)程,我們就簡(jiǎn)稱(chēng)為UI線(xiàn)程。UI線(xiàn)程內有個(gè)Dispatcher對象。Dispatcher對象內則包含這個(gè)UI線(xiàn)程的眾多工作內容(官方叫work item)的隊列。UI線(xiàn)程就是靠Dispatcher負責控件相關(guān)的這些事件的處理。廢話(huà)那么多,直接來(lái)個(gè)圖比較粗暴:

  3)只有創(chuàng )建了UI控件的UI Thread才有權限控制控件的訪(fǎng)問(wèn)和更新?。?!

    4)其他線(xiàn)程(非直接創(chuàng )建你要訪(fǎng)問(wèn)和控制UI控件的線(xiàn)程)要訪(fǎng)問(wèn)和更新某個(gè)控件,必須通過(guò)創(chuàng )建這個(gè)控件的線(xiàn)程(一般就是UI線(xiàn)程)所關(guān)聯(lián)的Dispatcher來(lái)訪(fǎng)問(wèn)和更新這個(gè)控件。這也是為什么經(jīng)常會(huì )有this.Dispatcher.Invoke()的原因。

    說(shuō)這么多做一些試驗來(lái)驗證以上的理論知識。

    先做一個(gè)下面這樣子的WPF界面:

XAML非常簡(jiǎn)單,代碼如下:

<Grid> <Button VerticalAlignment="Center" HorizontalAlignment="Center" Width="100" Name="myBtn">Click Me</Button> </Grid>

C#后臺代碼如下:

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Thread trd = new Thread(myFun);// 創(chuàng )建一個(gè)新線(xiàn)程 trd.Start();// 啟動(dòng)一個(gè)新線(xiàn)程 } public void myFun() { myBtn.Content = "My Love"; } }

   運行,你會(huì )發(fā)現在新線(xiàn)程運行myFun()的時(shí)候出現InvalidOperationException,確實(shí)到了新線(xiàn)程里直接更新控件會(huì )出錯。

    因此,我們myFun將代碼改為:

public void myFun() { this.Dispatcher.Invoke(()=> { myBtn.Content = "My Love"; }); }

重新運行,線(xiàn)程正確無(wú)誤的修改了Button控件上的信息。

需要注意的是系統在MainWinow起來(lái)之后就給當前UI線(xiàn)程分配好了Dispatcher,這個(gè)Dispatcher屬于MainWindow這個(gè)實(shí)例的,原因在于MainWindow繼承自DispatcherObject類(lèi),而DispatcherObject包含了一個(gè)公共屬性Dispatcher。實(shí)際上不僅僅是Window類(lèi),其他控件也都繼承自DispatcherObject,因此他們在初始化時(shí)都自動(dòng)賦值了Dispatcher屬性,并且都指向同一個(gè)UI線(xiàn)程所擁有的Dispatcher對象。對于當前這例子,MainWindow和Button都被UI線(xiàn)程創(chuàng )建,并且MainWindow和Button的Dispatcher屬性都指向UI線(xiàn)程擁有的Dispatcher,因此,我們還可以將上面的例子改為下面的方式(用myBtn.Dispatcher.Invoke()來(lái)實(shí)現按鈕的更新,運行結果完全一樣):

public void myFun() { myBtn.Dispatcher.Invoke(()=> { myBtn.Content = "My Love"; }); }

    從代碼上看起來(lái),myFun函數內訪(fǎng)問(wèn)this.Dispatcher貌似訪(fǎng)問(wèn)的是運行myFun線(xiàn)程中的Dispatcher,看起來(lái)是有點(diǎn)古怪,不過(guò)你只要知道this指的是MainWindow實(shí)例對象,那么MainWindow這個(gè)類(lèi)實(shí)例對象的Dispatcher是UI線(xiàn)程擁有的對象,因此沒(méi)有錯誤,也就不古怪了。

    假如整個(gè)代碼改為下面的方式:

public MainWindow() { InitializeComponent(); myFun(); } public void myFun() { myBtn.Content = "My Love"; }

    我們發(fā)現,運行也沒(méi)問(wèn)題,沒(méi)有任何古怪的地方,加不加this.Dispatcher.Invoke()都可以運行ok。這是由于運行myFunc的環(huán)境是在UI線(xiàn)程之下。為了更容易發(fā)現線(xiàn)程的變換,我們加入更多的測試代碼,整個(gè)工程改為如下:

public MainWindow() { InitializeComponent(); Thread.CurrentThread.Name = "Main Thread";// 設置當前線(xiàn)程名稱(chēng) Thread trd = new Thread(myFun); // 創(chuàng )建一個(gè)新線(xiàn)程 trd.Name = "New Thread"; trd.Start(); // 啟動(dòng)一個(gè)新線(xiàn)程 } public void myFun() { this.Dispatcher.Invoke(() => { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 }); }

 我們發(fā)現,代碼運行到myFun()時(shí)的線(xiàn)程已經(jīng)變成了trd所創(chuàng )建的線(xiàn)程(通過(guò)Thread.CurrentThread.Name來(lái)獲知當前線(xiàn)程名稱(chēng)是個(gè)好辦法),新線(xiàn)程的名稱(chēng)也成功輸出到按鈕上:

 由此,我們應當樹(shù)立一個(gè)觀(guān)點(diǎn): 同一個(gè)類(lèi)下的方法根據你調用的方式不同,并不一定都運行于同一個(gè)線(xiàn)程下。即使調用其他類(lèi)的函數,也可能存在兩種情況,要么運行在一個(gè)線(xiàn)程里,要么運行在不同的線(xiàn)程里。實(shí)際上是否是一個(gè)線(xiàn)程里完全跟如何調度相關(guān),跟是否屬于哪個(gè)類(lèi)沒(méi)有任何關(guān)系。

    如果實(shí)在不清楚某個(gè)線(xiàn)程下是否可以直接更新或訪(fǎng)問(wèn)控件,一方面你可以一股腦的都加上this.Dispatcher.Invoke()(實(shí)際上除了這個(gè)方法,還有BeginInvoke方法),另一方面可以通過(guò)控件的CheckAccess()方法或者VerifyAccess()方法來(lái)判斷該控件是否允許在當前線(xiàn)程下被訪(fǎng)問(wèn)被更新。因此,myFun函數可以改為下面的形式:

public void myFun() { // myBtn.VerifyAccess(); //該方法在不可訪(fǎng)問(wèn)的情況下,直接拋出InvalidOperationException異常 if(!myBtn.CheckAccess()) { this.Dispatcher.Invoke(() => { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 }); } else { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 } } }

  有深究精神的童鞋,可能會(huì )問(wèn),既然某個(gè)線(xiàn)程擁有Dispatcher,那么是否可以通過(guò)線(xiàn)程直接訪(fǎng)問(wèn)Dispatcher呢?這個(gè)很簡(jiǎn)單,可以直接查找Thread線(xiàn)程類(lèi)的資料,驚奇的發(fā)現,Thread根本不存在一個(gè)可以訪(fǎng)問(wèn)自身所擁有的Dispatcher對象的屬性或者方法,搞得我也一頭霧水,反正有一種"我擁有的還不能直接獲得"的莫名其妙感覺(jué)。那有沒(méi)有能獲得的辦法了呢?答案是肯定的。

    可以通過(guò)Dispatcher類(lèi)本身的static方法FromThread(Thread trd)來(lái)獲得某個(gè)線(xiàn)程所擁有的Dispatcher。下面將c#后臺代碼改為下面的試驗代碼:

public MainWindow() { InitializeComponent(); Dispatcher dsp = Dispatcher.FromThread(Thread.CurrentThread);//結果:非null bool r = dsp.Equals(this.Dispatcher);//結果:true Thread.CurrentThread.Name = "Main Thread";// 設置當前線(xiàn)程名稱(chēng) Thread trd = new Thread(myFun); // 創(chuàng )建一個(gè)新線(xiàn)程 trd.Name = "New Thread"; trd.Start(); // 啟動(dòng)一個(gè)新線(xiàn)程 } public void myFun() { Dispatcher dsp = Dispatcher.FromThread(Thread.CurrentThread);//結果:獲得的dsp值為null if (!myBtn.CheckAccess()) { this.Dispatcher.Invoke(() => { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 }); } else { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 } }

用debug調試方式,你會(huì )發(fā)現在MainWindow構造函數下的函數中獲得的dsp非空,并且通過(guò)Equals()方法發(fā)現dsp就是this.Dispatcher。myFun()函數運行的線(xiàn)程下,dsp的結果是空,明顯就不等于this.Dispatcher。

那么怎么給這個(gè)新的線(xiàn)程賦一個(gè)Dispatcher?

可能我看的資料還沒(méi)全,至今我還只發(fā)現一種辦法,并且是一種讓人感覺(jué)很莫名其妙或者說(shuō)很隱晦的方法,直接上代碼:

public MainWindow() { InitializeComponent(); Dispatcher dsp = Dispatcher.FromThread(Thread.CurrentThread);//結果:非null bool r = dsp.Equals(this.Dispatcher);//結果:true Dispatcher newdsp = Dispatcher.CurrentDispatcher; // 獲取當前的Dispatcher r = this.Dispatcher.Equals(newdsp); //結果,仍然是true,說(shuō)明已經(jīng)有Dispatcher的情況下不會(huì )賦新Dispatcher Thread.CurrentThread.Name = "Main Thread";// 設置當前線(xiàn)程名稱(chēng) Thread trd = new Thread(myFun); // 創(chuàng )建一個(gè)新線(xiàn)程 trd.Name = "New Thread"; trd.Start(); // 啟動(dòng)一個(gè)新線(xiàn)程 } public void myFun() { Dispatcher dsp = Dispatcher.FromThread(Thread.CurrentThread);//結果:獲得的dsp值為null Dispatcher newdsp = Dispatcher.CurrentDispatcher; // 默默的為當前新線(xiàn)程賦了一個(gè)Dispatcher dsp = Dispatcher.FromThread(Thread.CurrentThread); // 重新獲取當前線(xiàn)程的Dispatcher bool r = newdsp.Equals(dsp);// 結果是true if (!myBtn.CheckAccess()) { this.Dispatcher.Invoke(() => { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 }); } else { myBtn.Content = Thread.CurrentThread.Name;// 將當前線(xiàn)程名稱(chēng)輸出到Button上 } }

 仔細看上面的代碼及注釋。

   官網(wǎng)透露的資料里,告訴我們既可以通過(guò)Dispatcher.CurrentDispatcher獲得當前線(xiàn)程的Dispatcher對象,也可以通過(guò)訪(fǎng)問(wèn)Dispatcher.CurrentDispatcher(CurrentDispatcher只可讀!!!)給一個(gè)沒(méi)有Dispatcher的線(xiàn)程自動(dòng)賦一個(gè)Dispatcher,自動(dòng)給一個(gè)無(wú)Dispatcher的線(xiàn)程賦一個(gè)Dispatcher對象這個(gè)功能顯得比較古怪,但是微軟就是這么任性。

    根據官網(wǎng)資料,一旦一個(gè)線(xiàn)程獲得了一個(gè)Dispatcher,那么這個(gè)Dispatcher不可更改,即使被關(guān)閉。

    不過(guò),個(gè)人還不是很清楚給一個(gè)不帶界面的Thread賦一個(gè)Dispatcher的作用,貌似沒(méi)什么作用。要么就是鄙人還沒(méi)掌握所有資料。

    今天的故事就先講到這里了。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
WPF:如何在工作線(xiàn)程中更新窗體的UI元素(Dispatcher機制)
WPF 基礎到企業(yè)應用系列3——Dispatcher及多線(xiàn)程
C# this.Invoke()的作用與用法
DispatcherTimer與Dispatcher小小應用
C#執行異步操作的幾種方式比較和總結
android——淺談歸納Handler各種用法
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久