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