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