我使用CodePlex和Bea Stollnitz的博客以及Vincent Da Ven Berhge的論文(同一鏈接)的一些想法實施了數據虛擬化解決方案。不過,我需要一種不同的方法,所以我決定寫我自己的解決方案。帶數據虛擬化的DataGrid行請求模式
我使用DataGrid
來顯示大約一百萬行使用此解決方案。我也在使用UI虛擬化。我的解決方案是可行的,但在某些情況下,我在DataGrid
如何從其源請求數據時遇到一些奇怪的行爲。
關於解決方案
我寫了一份清單,完成所有繁重的工作。它是一個通用類,名稱爲VirtualList<T>.
它實現了ICollectionViewFactory
接口,因此集合視圖創建機制可以創建一個實例來包裝它。這個類繼承自ListCollectionView
。我沒有按照建議編寫自己的ICollectionView
實現。繼承似乎也很好。
VirtualList<T>
將整個數據分成頁面。它獲取總項目數,每當DataGrid
通過列表索引器請求一行時,它會加載適當的頁面或從緩存中返回。頁面在內部被回收,並且在空閒時間處理未使用的頁面。
數據請求模式
我學到的第一件事,是
VirtualList<T>
應該實現IList
(非通用)。否則ItemsControl
會將其視爲IEnumerable
並查詢/枚舉所有行。這是合乎邏輯的,因爲DataGrid
不是類型安全的,所以它不能使用接口IList<T>
。具有0索引的行經常被
DataGrid
詢問。它似乎被用於視覺項目測量(根據調用堆棧)。所以,我只是緩存這一個。DataGrid
中的高速緩存機制使用可預測的模式來查詢它顯示的行。首先它要求可見行從上到下(每行兩次),然後在可見區域(包括第一個可見行)下降之前查詢幾行(取決於可見區域的大小)從底部到頂部訂購。之後,它會在可見行(包括最後一個可見行)之後從上到下請求相同數量的行。如果可見行索引是4,5,6。數據請求將是:4,4,5,5,6,6,4,3,2,1,6,7,8,9。
如果我的頁面大小設置正確,我可以從當前頁面和先前加載的頁面提供所有這些請求。
如果
CanSelectMultipleItems
是True
並且用戶選擇使用SHIFT鍵或鼠標拖動多個項目,則DataGrid
枚舉從列表中選擇的端部的開始的所有行。無論IList
是否實施,此枚舉都通過IEnumerable
接口進行。如果所選行不可見並且當前可見區域與所選行相距「很遠」,則有時DataGrid會開始請求從選定行到可見區域結束的所有項目。包括它們之間甚至不可見的所有行。我無法弄清楚這種行爲的確切模式。也許我的實現是這個原因。
我的問題
我很納悶,爲什麼
DataGrid
請求不可見行,因爲當成爲可見的那些行會再次請求?爲什麼有必要請求每行兩到三次?
誰能告訴我如何使DataGrid不使用
IEnumerable
,除了關閉多項選擇?
是的,我最終做了類似的事情。我返回了我已經加載的所有物品,沒有其他物品。自那以後沒有造成問題。謝謝 –