Ho implementato una soluzione di virtualizzazione dei dati utilizzando alcune idee da CodePlex e il blog di Bea Stollnitz e il documento di Vincent Da Ven Berhge (stesso collegamento). Tuttavia, avevo bisogno di un approccio diverso, quindi ho deciso di scrivere la mia soluzione.Pattern di richiesta riga DataGrid con virtualizzazione dei dati
Sto utilizzando uno DataGrid
per visualizzare circa un milione di righe con questa soluzione. Sto anche usando la virtualizzazione dell'interfaccia utente. La mia soluzione è fattibile, ma ho riscontrato alcuni strani comportamenti in determinate situazioni su come il DataGrid
richieda i dati dalla sua origine.
Circa la soluzione
ho finito per scrivere una lista che fa tutto il lavoro pesante. Si tratta di una classe generica denominata VirtualList<T>.
Implementa l'interfaccia ICollectionViewFactory
, pertanto il meccanismo di creazione della vista di raccolta può creare un'istanza VirtualListCollectionView<T>
per includerla. Questa classe eredita da ListCollectionView
. Non ho seguito i suggerimenti per scrivere la mia implementazione ICollectionView
. Anche l'ereditarietà funziona bene.
Il VirtualList<T>
divide l'intero dato in pagine. Ottiene il conteggio totale delle voci e ogni volta che le richieste di una riga DataGrid
tramite l'indicizzatore di elenco carica la pagina appropriata o la restituisce dalla cache. Le pagine vengono riciclate all'interno e un DispatcherTimer
dispone le pagine non utilizzate in idle time.
modelli di richiesta dati
La prima cosa che ho imparato, che
VirtualList<T>
dovrebbero attuareIList
(non generico). In caso contrario, loItemsControl
lo considererà come unIEnumerable
e interrogherà/enumererà tutte le righe. Questo è logico, dal momento che loDataGrid
non è sicuro, quindi non può usare l'interfacciaIList<T>
.La riga con indice 0 viene spesso richiesta dal numero
DataGrid
. Sembra essere usato per la misurazione degli oggetti visivi (secondo lo stack di chiamate). Quindi, ho semplicemente messo in cache questo.Il meccanismo di memorizzazione nella cache all'interno di
DataGrid
utilizza un modello prevedibile per interrogare le righe che mostra. Prima chiede le righe visibili dall'alto verso il basso (due volte per ogni riga), quindi interroga un paio di righe (a seconda della dimensione dell'area visibile) prima dell'area visibile (inclusa la prima riga visibile) in una discendente ordina così, dal basso verso l'alto. Dopodiché richiede lo stesso numero di righe dopo le righe visibili (inclusa l'ultima riga visibile) dall'alto verso il basso.Se gli indici di riga visibili sono 4,5,6. La richiesta di dati sarebbe: 4,4,5,5,6,6,4,3,2,1,6,7,8,9.
Se la dimensione della pagina è impostata correttamente, posso soddisfare tutte queste richieste dalla pagina corrente e caricata in precedenza.
Se
CanSelectMultipleItems
èTrue
e l'utente seleziona più voci utilizzando il tasto MAIUSC o trascinamento del mouse, ilDataGrid
enumera tutte le righe dall'inizio della lista alla fine della selezione. Questa enumerazione avviene tramite l'interfacciaIEnumerable
indipendentemente dal fatto che sia implementato o menoIList
.Se la riga selezionata non è visibile e l'area visibile corrente è "lontana" dalla riga selezionata, a volte DataGrid inizia a richiedere tutti gli elementi, dalla riga selezionata alla fine dell'area visibile. Comprese tutte le righe intermedie che non sono nemmeno visibili. Non riuscivo a capire il modello esatto di questo comportamento. Forse la mia implementazione è la ragione per questo.
Le mie domande
Mi chiedo, perché i
DataGrid
richieste di file non visibili, dal momento che tali file verranno richiesti nuovamente quando diventano visibili?Perché è necessario richiedere ogni riga due o tre volte?
Qualcuno può dirmi come rendere DataGrid non utilizzare
IEnumerable
, ad eccezione della disattivazione della selezione di più elementi?
Sì, in realtà ho finito per fare qualcosa di simile. Ritorna tutti gli oggetti che ho già caricato e nient'altro. Non ha causato problemi da allora. Grazie –