WPF線程渲染相關(guān)疑難問(wèn)題解答
WPF開(kāi)發(fā)工具為我們帶來(lái)了一個(gè)新的開(kāi)發(fā)環(huán)境。在解決圖形界面顯示方面起到了很大的作用,可以方便的使我們開(kāi)發(fā)出與MAC一樣的圖形界面。#t#
今天又看到了WPF線程渲染的問(wèn)題,之所以存在UI線程問(wèn)題,其實(shí)還是在線程模型上來(lái)說(shuō),直接對(duì)另一個(gè)線程的操作會(huì)帶來(lái)隱患,比方說(shuō),UI線程正在渲染A,我們直接操作A的數(shù)據(jù)會(huì)導(dǎo)致渲染的結(jié)果和實(shí)際數(shù)據(jù)不一致,說(shuō)通俗點(diǎn)兒,就是界面上我們看到的數(shù)據(jù)并不是實(shí)際的數(shù)據(jù)(寒~~我說(shuō)得都有點(diǎn)兒暈了!)之前,我寫過(guò)文章,講述了幾個(gè)如何修改UI數(shù)據(jù)從其他線程,但是,畢竟是從技巧層面上去遷就,始終感覺(jué)有些不妥,籍著重構(gòu)代碼時(shí)的思路,就在這里感慨一下。
其實(shí),徹底解決WPF線程渲染這個(gè)問(wèn)題并不困難,首先要理清自己系統(tǒng)中各個(gè)層和各個(gè)模塊的分工,讓我們回憶一下,SOA面向服務(wù)的架構(gòu)優(yōu)越性不言而喻,實(shí)現(xiàn)的困難關(guān)鍵在于如何去實(shí)現(xiàn)一個(gè)企業(yè)總線,而這個(gè)企業(yè)總線的思路,其實(shí)就是把數(shù)據(jù)的使用和數(shù)據(jù)的操作做個(gè)分離。在傳統(tǒng)的三層架構(gòu),我們通常分為表現(xiàn)層、邏輯層、數(shù)據(jù)層,表現(xiàn)層來(lái)存儲(chǔ)數(shù)據(jù),邏輯層來(lái)控制業(yè)務(wù)邏輯,數(shù)據(jù)層來(lái)存儲(chǔ)管理數(shù)據(jù)。
如果,我們的設(shè)計(jì)能夠如此清晰,我們就不會(huì)存在需要在表現(xiàn)層里使用的數(shù)據(jù)在邏輯層或數(shù)據(jù)層里修改,為什么呢?因?yàn)椋瑢雍蛯又g不能存在耦合,否則就失去了分層的意義和價(jià)值,例如:表現(xiàn)層需要展示產(chǎn)品A的信息,向邏輯層要產(chǎn)品A的數(shù)據(jù),產(chǎn)品A的數(shù)據(jù)被邏輯層過(guò)濾選擇之后傳遞出來(lái),傳遞的是值而不是一個(gè)引用,這一點(diǎn)非常重要!!
如果傳遞的是引用會(huì)怎么樣呢?傳遞引用會(huì)造成數(shù)據(jù)只能由生成該實(shí)例的線程進(jìn)行操作,否則,存在跨線程操作的安全問(wèn)題,例如UI線程生成實(shí)例,無(wú)法在邏輯層線程中修改,而邏輯層線程生成的數(shù)據(jù)實(shí)例也同樣無(wú)法在UI線程中進(jìn)行修改,回歸了我們的題目:”徹底解決UI跨線程操作問(wèn)題
“我們之所以會(huì)從邏輯層參會(huì)數(shù)據(jù)引用而不返回一個(gè)數(shù)據(jù)的拷貝(值類型拷貝),最主要的原因是我們被數(shù)據(jù)綁定迷惑了,我們太依賴于數(shù)據(jù)綁定帶來(lái)的好處,但是,使用的思路差異會(huì)帶來(lái)本質(zhì)的不同。如果,我們把數(shù)據(jù)綁定只是在表現(xiàn)層中使用,而不是為了方便,把來(lái)自于邏輯層的數(shù)據(jù)結(jié)構(gòu)引用綁定到表現(xiàn)層,在表現(xiàn)層綁定顯示之后,如果不是Once綁定,數(shù)據(jù)在任何時(shí)候發(fā)生的改變都會(huì)自動(dòng)呈現(xiàn)在界面上。
事實(shí)并非如此!!!我們只是一廂情愿而已,上述的情況只是一種理想的假設(shè),而這個(gè)理想的假設(shè)帶來(lái)了UI跨線程操作的問(wèn)題。回想一下,我們當(dāng)初開(kāi)發(fā)Win32應(yīng)用程序時(shí),我們會(huì)給界面中一個(gè)控件的Text屬性賦值,但是我們會(huì)在后臺(tái)線程中操作這個(gè)Text屬性,我們希望數(shù)據(jù)的改變被呈現(xiàn)在界面中,但卻因?yàn)榭缇€程操作而出錯(cuò),這時(shí)候,正確的操作應(yīng)該是,UI線程在輪詢或監(jiān)聽(tīng)一個(gè)后臺(tái)線程的時(shí)間,一旦數(shù)據(jù)改變,由UI線程來(lái)進(jìn)行數(shù)據(jù)的修改,這樣就不會(huì)出錯(cuò)了。
同理,在我們開(kāi)發(fā)Silverlight的時(shí)候,我們也帶著這樣的思路,無(wú)論是綁定還是任何形式的數(shù)據(jù)呈現(xiàn),呈現(xiàn)所在的WPF線程渲染生成數(shù)據(jù)實(shí)例同時(shí)管理數(shù)據(jù)內(nèi)容,這樣就永遠(yuǎn)不會(huì)出現(xiàn)跨線程操作的問(wèn)題,只要在邏輯層稍作修改即可,通過(guò)監(jiān)聽(tīng)底層數(shù)據(jù)改變,并把自己當(dāng)作一個(gè)Proxy透?jìng)鬟@些數(shù)據(jù)改變給UI線程,UI線程來(lái)決定什么時(shí)候修改數(shù)據(jù),問(wèn)題就徹底解決了。