WPF的UI虛擬化


許多時候,我們的界面上會呈現大量的數據,如包含數千條記錄的表格或包含數百張照片的相冊。由於呈現UI是一件開銷比較大的動作,一次性呈現數百張照片就目前的電腦性能來說是需要占用大量內存和時間的。因此需要對其進行優化。以前采用的方案大多數是翻頁,翻頁在某種程度上造成用戶瀏覽的中斷,因此現在往往采用一種新的方案——UI虛擬化。

UI虛擬化的原理是:但是由於顯示器和人眼的限制,用戶往往只會同時看到其中的數十條數據,因此只要在界面上渲染用戶所看到的那些數據即可,對於用戶呈現的界面仍然是一樣的。微軟的MSDN文檔UI虛擬化說明的比較詳細,這里就不累述了。

關於UI虛擬化的實現,其核心則是VirtualPanel,在WPF中內置的VirtualPanel貌似只有VirtualizingStackPanel一個,不過這個也是最實用的,一般常用於表格之類的數據呈現。如果需要其它布局方式的Panel,則需要自己實現,MSDN Blog上有一系列文章介紹得比較詳細:

文章最后也附帶了一個VirtualizingTilePanel,實現了一個類似WrapPanel的效果(它要求里面的元素大小是相等的)。用於照片瀏覽之類的持續還是比較方便的,不知道為什么M$官方沒有帶這個。原文的.Net版本比較老,是直接編譯不過去的,需要自行修改一下。

 

實現自定義VirtualizingPanel並非很復雜,首先介紹介紹幾個前置條件:

1. VirtualizingPanel是用於UI虛擬化的,它是用來做ItemsControl的ItemTemplate的,而不是像普通Panel那樣直接控制Children。因此,它必須同ItemsControl及其子類(如DataGrid、ListBox)搭配使用,並繼承自VirtualizingPanel。

2. VirtualizingPanel是需要和ScrollViewer一起使用的,沒有ScrolViewer的話,所有控件都是可見的,談不上虛擬化。需要注意的是,ItemsControl的默認Template沒有ScrollViewer,在ItemsControl中使用VirtualizingPanel時,需要修改一下Template,加上ScrollViewer,並設置CanContentScroll="True"。

3. UI虛擬化是需要在不呈現所有的UI控件前提下知道當前視圖下元素呈現效果的,如果所有的數據都轉換了為控件的話,也就談不上虛擬化了。也就是說,不能靠Measure和Arrange所有子元素來確定布局。

 

具體實現的時候一般有如下幾個功能點:

  1. Panel需要實現IScrollInfo接口,這樣才能手動控制滾動時候的界面虛擬化。關於IScrollInfo接口,我前面的文章中有一些介紹,可以參考一下。
  2. Panel需要能只根據數據感知整體的布局。常見的有三種方案:1. 在Panel中直接指定每個子元素所占據的空間大小,2. 拿第一個子元素所占據的大小來衡量其它子元素所占據的大小,3.數據中直接聲明它所需要的大小
  3. Panel根據當前窗口的大小呈現元素(加載可見元素,刪除不可見元素)。

例子就可以直接參考前面的那個,這里就不單獨舉例了。

  

數據虛擬化:

UI虛擬化可以解決渲染UI控件所需要較多的時間和內存的問題,但是還是有可以優化的空間,那就是所有的數據仍然都加載到了內存中了。我們仍然可以采用和UI虛擬化一樣的優化方案:不加載所有數據到集合,只加載用戶可見部分。數據虛擬化本身並不受WPF所支持,不過當我們的Panel實現IScrollInfo接口了之后,就可以精確感知滾動條了,實現數據虛擬化也不是難事。

一般來說,我們很少使用數據虛擬化,主要的原因是它大多數的時候只能減少很少一點內存占用,反而帶來了較大的代碼復雜度, 一般是認為得不償失的。

不過,有的時候,我們的數據是來自於外部RPC訪問,這個時候數據虛擬化就有意義了,考慮如下兩個場景:

  1. 新聞客戶端,數據來源是來自於遠程的Rest服務,但是它的接口是分頁獲取的,只能每次獲取50條,總共卻可能有100頁。
  2. 圖片瀏覽器,圖片不是來自於本地,而是來自於圖片服務網站。

第一個例子就是比較典型的數據虛擬化的應用場景了,如果一開始就加載所有100頁新聞就需要花費大量時間了。第二個例子則是部分數據虛擬化,圖片信息無需虛擬化,但圖片呈現需要虛擬化,只是在需要呈現的時候才從網絡下載。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM