Virtualizzazione dei dati in ListView e GridView
NotaPer altri dettagli, vedi la sessione di //build/ dedicata a come migliorare sensibilmente le prestazioni quando gli utenti interagiscono con grandi quantità di dati in GridView e ListView.
Migliorare le prestazioni e i tempi di avvio di ListView e GridView tramite la virtualizzazione dei dati. Per la virtualizzazione dell'interfaccia utente, la riduzione degli elementi e l'aggiornamento progressivo di elementi, vedere Ottimizzazione dell'interfaccia utente in ListView e GridView.
È necessario un metodo di virtualizzazione dei dati per i set di dati così grandi che non possono o non dovrebbero essere archiviati in memoria tutti contemporaneamente. Si può caricare una parte iniziale in memoria (da disco locale, rete o cloud) e applicare la virtualizzazione dell'interfaccia utente al set di dati parziale. In un secondo momento sarà possibile scaricare i dati gradualmente o da punti arbitrari nel set di dati master (accesso casuale), su richiesta. Il fatto che la virtualizzazione dei dati sia appropriata per le tue esigenze dipende da molti fattori.
- Le dimensioni del set di dati
- Le dimensioni di ogni elemento
- L'origine del set di dati (disco locale, rete o cloud)
- Utilizzo complessivo della memoria dell'app
Nota Tenere presente che una funzionalità è abilitata per impostazione predefinita per ListView e GridView che visualizza gli oggetti visivi segnaposto temporanei mentre l'utente esegue la panoramica/scorrimento rapido. Man mano che i dati vengono caricati, questi elementi visivi segnaposto vengono sostituiti con il modello di elemento. È possibile disattivare la funzionalità impostando ListViewBase.ShowsScrollingPlaceholders su false, ma in tal caso è consigliabile usare l'attributo x:Phase per eseguire il rendering progressivo degli elementi nel modello di elemento. Vedere Aggiornare gli elementi ListView e GridView in modo progressivo.
Ecco altri dettagli sulle tecniche di virtualizzazione dei dati incrementale e con accesso casuale.
Virtualizzazione dei dati incrementale
La virtualizzazione incrementale dei dati carica i dati in sequenza. Un controllo ListView che usa la virtualizzazione dei dati incrementale può essere usato per visualizzare una raccolta di un milione di elementi, ma inizialmente ne vengono caricati solo 50. Quando l'utente esegue la panoramica/scorrimento, vengono caricati i 50 successivi. Man mano che procede il caricamento, diminuiscono le dimensioni del cursore della barra di scorrimento. Per questo tipo di virtualizzazione dei dati è necessario scrivere una classe origine dati che implementa queste interfacce.
- IList
- INotifyCollectionChanged (C#/VB) o IObservableVector<T> (C++/CX)
- ISupportIncrementalLoading
Un'origine dati come questa è un elenco in memoria che può essere esteso continuamente. Il controllo elementi richiederà gli elementi tramite l'indicizzatore IList e le proprietà di conteggio standard. Il conteggio dovrebbe rappresentare il numero di elementi in locale e non la dimensione effettiva del set di dati.
Quando il controllo elementi si avvicina alla fine di dati esistenti, chiamerà ISupportIncrementalLoading.HasMoreItems. Se restituisci true, allora chiamerà ISupportIncrementalLoading.LoadMoreItemsAsync passando un numero consigliato di elementi da caricare. A seconda dell'origine di caricamento dei dati (disco locale, rete o cloud), potresti scegliere di caricare un numero diverso di elementi rispetto a quello consigliato. Ad esempio, se il servizio supporta batch di 50 elementi, ma il controllo elementi ne richiede solo 10, allora puoi caricarne 50. Carica i dati dal tuo back-end, aggiungili all'elenco e genera una notifica di modifica tramite INotifyCollectionChanged o IObservableVector<T> in modo che il controllo elementi sia a conoscenza dei nuovi elementi. Restituisci anche un conteggio degli elementi effettivamente caricati. Se carichi meno elementi rispetto al numero consigliato oppure se nel frattempo lo scorrimento del controllo elementi va oltre, l'origine dati verrà chiamata di nuovo per recuperare altri elementi e il ciclo continuerà. Per altre informazioni, scarica l'esempio di data binding XAML per Windows 8.1 e riutilizza il codice sorgente nella tua app di Windows 10.
Virtualizzazione dei dati con accesso casuale
La virtualizzazione dei dati con accesso casuale consente il caricamento da un punto arbitrario nel set di dati. Un controllo ListView che usa la virtualizzazione dei dati con accesso casuale, usato per visualizzare una raccolta di un milione di elementi, può caricare gli elementi da 100.000 a 100.050. Se l'utente si sposta poi all'inizio dell'elenco, il controllo carica gli elementi da 1 a 50. In ogni momento, il cursore della barra di scorrimento indica che il controllo ListView contiene un milione di elementi. La posizione del cursore della barra di scorrimento è relativa alla posizione degli elementi visibili nell'intero set di dati della raccolta. Questo tipo di virtualizzazione dei dati può ridurre in modo significativo i requisiti di memoria e i tempi di caricamento per la raccolta. Per abilitarla, è necessario scrivere una classe origine dati che recupera i dati su richiesta e gestisce una cache locale e implementa queste interfacce.
- IList
- INotifyCollectionChanged (C#/VB) o IObservableVector<T> (C++/CX)
- (Facoltativo) IItemsRangeInfo
- (Facoltativo) ISelectionInfo
IItemsRangeInfo fornisce informazioni sugli elementi effettivamente in uso nel controllo. Il controllo elementi chiamerà questo metodo per ogni cambio di visualizzazione e includerà questi due set di intervalli.
- Il set di elementi presenti nel riquadro di visualizzazione.
- Un set di elementi non virtualizzati usati dal controllo, che potrebbero non essere nel riquadro di visualizzazione.
- Un buffer di elementi attorno al riquadro di visualizzazione mantenuto dal controllo elementi in modo che la panoramica tramite tocco risulti fluida.
- L'elemento con lo stato attivo.
- Il primo elemento.
Implementando IItemsRangeInfo, l'origine dati sa quali elementi devono essere recuperati e memorizzati nella cache e quando eliminare dalla cache i dati non più necessari. IItemsRangeInfo usa oggetti ItemIndexRange per descrivere un set di elementi in base al rispettivo indice nella raccolta. In questo modo non vengono usati puntatori agli elementi, che potrebbero non essere corretti o stabili. IItemsRangeInfo è progettato per l'uso da una singola istanza di un controllo elementi, perché si basa sulle informazioni di stato per tale controllo elementi. Se più controlli elementi devono accedere agli stessi dati sarà necessaria un'istanza separata dell'origine dati per ognuno. Possono condividere una cache comune, ma la logica per l'eliminazione dalla cache sarà più complessa.
Ecco la strategia di base per l'origine dati per la virtualizzazione dei dati con accesso casuale.
- Quando viene richiesto un elemento
- Se è disponibile in memoria, restituiscilo.
- Se non è disponibile, restituisci null oppure un elemento segnaposto.
- Usa la richiesta per un elemento (o le informazioni sull'intervallo di IItemsRangeInfo) per scoprire quali elementi sono necessari e per recuperare i dati per gli elementi dal tuo back-end in modo asincrono. Dopo aver recuperato i dati, genera una notifica di modifica tramite INotifyCollectionChanged o IObservableVector<T> in modo che il controllo elementi sia a conoscenza dei nuovi elementi.
- Facoltativo: quando cambia il riquadro di visualizzazione del controllo elementi, identifica gli elementi necessari dall'origine dati tramite la tua implementazione di IItemsRangeInfo.
A parte questo aspetto, la strategia per decidere quando caricare gli elementi di dati, quanti caricarne e quanti mantenerne in memoria dipende dalla tua applicazione. Alcune considerazioni generali di cui tenere conto:
- Effettua richieste asincrone per i dati, non bloccare il thread dell'interfaccia utente.
- Individua le dimensioni ideali dei batch in cui recuperare gli elementi. Trova il giusto equilibrio. Evita batch troppo piccoli che implicano un numero eccessivo di piccole richieste e batch troppo grandi che richiedono troppo tempo per il recupero.
- Considera il numero di richieste che vuoi avere in sospeso contemporaneamente. L'esecuzione di una richiesta alla volta è più facile, ma potrebbe essere troppo lenta se i tempi di elaborazione sono elevati.
- Puoi annullare le richieste di dati?
- Se usi un servizio ospitato, è previsto un costo per transazione?
- Che tipo di notifiche vengono fornite dal servizio quando vengono modificati i risultati di una query? Avrai modo di sapere se un elemento viene inserito in corrispondenza dell'indice 33? Se il tuo servizio supporta query basate su chiave-più-offset, queste potrebbero rappresentare un'alternativa migliore rispetto all'uso di un indice.
- Quanto deve essere intelligente la prelettura degli elementi? Hai intenzione di provare a tenere traccia della direzione e della velocità di scorrimento per prevedere quali elementi sono richiesti?
- Quanto vuoi essere aggressivo nell'eliminazione degli elementi dalla cache? Si tratta di trovare il giusto compromesso tra memoria ed esperienza.