2009-05-12 15 views
22

Sto lavorando a un'app wpf che contiene un elenco di righe con un numero elevato di dati (da 10.000 a 100.000). L'utente può applicare tutti i tipi di filtri a questa lista, rendendo la logica del filtro abbastanza avanzata (e lenta). Per il momento, la parte rilevante del mio codice è simile al seguente:ICollectionView.filter di WPF con grandi serie di dati

ICollectionView view = CollectionViewSource.GetDefaultView(hugeList.ItemsSource); 
view.Filter = new Predicate<object>(FilterCallback); 

private bool FilterCallback(object item) 
{ 
    //Filter logic 
} 

Ma questo viene eseguito nel thread dell'interfaccia utente e blocca l'intera applicazione quando il filtraggio che dà un'esperienza utente molto povera. Quindi la mia domanda a voi tutti è: qualcuno sa un modo "migliore" per filtrare un listview in wpf o dovrei filtrare il sottostante ObservableCollection?

+0

+1 Buona domanda! Che soluzione hai trovato? – gehho

+0

È possibile che il problema di prestazioni si trovi nella griglia di rilegatura/rendering delle cose e non correlato alla logica effettiva del filtro ... – Schneider

risposta

20

Prestare particolare attenzione alla funzione del filtro. Assicurati di non fare nessun box/unboxing non necessario e non stai facendo calcoli estesi. Dovresti anche prestare attenzione al tipo di ViewView che stai utilizzando, alcuni sono più veloci di altri. Da Bea's post on sorting:

  • Un CollectionView viene creata se la vostra fonte implementa IEnumerable. Se la fonte implementa IEnumerable solo, non sarà possibile ordinare o raggruppare la raccolta (è possibile filtrarla solo). Inoltre, perf non sarà il migliore se la fonte ha un numero elevato di elementi o se esegui operazioni dinamiche come inserimenti e cancellazioni. Se questo è il tuo scenario, dovresti considerare che la tua fonte implementa un'interfaccia più forte. ICollection è leggermente migliore perché fornisce una proprietà Count.

  • ListCollectionView è il tipo di vista creato quando l'origine implementa IList. Rispetto a IEnumerable e ICollection, IList si comporta molto meglio per gli elenchi di grandi dimensioni o dinamici perché fornisce un indicizzatore, consentendoci un accesso casuale rapido. Inoltre, IList consente l'ordinamento, il raggruppamento e il filtraggio. Ma idealmente la tua raccolta di fonti deriva da ObservableCollection, la madre di tutte le raccolte agli occhi del binding di dati, poiché fornisce numerosi extra extra come notifiche di modifica della proprietà e della raccolta.

  • BindingListCollectionView è il tipo di vista creato da Avalon quando la raccolta di origine implementa IBindingList. Questa è la vista che trattiamo nello scenario ADO.NET. Supporta l'ordinamento e il raggruppamento, ma non il filtraggio tradizionale. Al contrario, ha una proprietà CustomFilter aggiuntiva che delega il filtraggio al DataView (vedi il mio post su ADO.NET per maggiori dettagli).

È possibile calciare il filtraggio per un thread diverso da @mihi detto ma ho usato CollectionViews di eseguire più filtri contemporaneamente su un ObservableCollection con 50.000 voci di un oggetto con ~ 60 variabili (colonne di una tabella di database) senza ritardo evidente.

Una cosa che noto immediatamente nella funzione del filtro è l'input di tipo Object che probabilmente significa che si sta eseguendo una conversione di tipo all'interno della funzione e potrebbe non essere necessario. Inoltre, si utilizza Predicato che non include un tipo restituito, quindi probabilmente richiede alcune conversioni o riflessioni di tipo all'interno dei metodi di filtraggio di CollectionView e potrebbe rallentare anche l'utente.

+2

Potresti aggiungere qualche codice di esempio per mostrare come spostare il filtro su un thread diverso? Non riesco a farlo funzionare su un thread diverso. – Luke

+5

@Bryan: ho una situazione simile e vorrei migliorare le mie prestazioni del filtro. Nella tua risposta hai scritto che si dovrebbe evitare di usare un "Predicato " perché richiede operazioni di box/unboxing e non include un tipo di ritorno. Cosa intendi esattamente con questo? Ha un tipo di ritorno di 'bool', e deve essere un' Predicate 'perché la proprietà' Filter' di 'ListCollectionView' è definita in questo modo. C'è un modo per aggirare questo e usare un altro approccio al filtro? O quale era la tua intenzione? Forse ho appena frainteso ... – gehho

+0

@gehho Penso che stavo solo buttando fuori le idee al momento per cose che potrebbero causare un rallentamento. 99 volte su 100 sarà una cosa lenta nella logica di filtraggio che sta causando il problema. –

3

Hai considerato il filtraggio in un'altra discussione o l'utilizzo del dispatcher?

WPF Threads: Build more responsive apps with the dispatcher offre una panoramica di alcune delle opzioni di threading disponibili.

+1

L'ho preso in considerazione, ma non riesco ad accedere a "ICollectionView" in un thread diverso da Thread dell'interfaccia utente? –

+2

No, ma è possibile eseguire la logica di filtraggio in un altro thread e modificare la raccolta sul thread dell'interfaccia utente utilizzando Dispatcher.Invoke –

+1

Ecco un buon esempio di questa soluzione: http://www.codeproject.com/Articles/32426/Deferring- ListCollectionView-filter-updates-for-a –

Problemi correlati