1. 程式人生 > >WPF的UI虛擬化

WPF的UI虛擬化

原文: WPF的UI虛擬化

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

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

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

  1. Implementing a VirtualizingPanel part I
  2. Implementing a VirtualizingPanel part II
  3. Implementing a VirtualizingPanel part III
  4. Implementing a VirtualizingPanel part IV

文章最後也附帶了一個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頁新聞就需要花費大量時間了。第二個例子則是部分資料虛擬化,圖片資訊無需虛擬化,但圖片呈現需要虛擬化,只是在需要呈現的時候才從網路下載。