Domanda

ho un ObservableCollection di ViewModels che si trovano in un WPF DataGrid.IL DataGrid ha tre colonne:

  • Colonna posizione;questo viene reso in fase di esecuzione da un UserControl che visualizza la posizione della riga nel mio DataGrid
  • Colonna nome;questo viene visualizzato in fase di esecuzione da un UserControl che visualizza il nome della colonna (sì, ho bisogno di un UserControl per questo in base a come deve essere visualizzato il nome, ma questo è un aspetto a parte)
  • Colonna dati;questo viene reso in fase di esecuzione da un altro UserControl.

Le mie colonne sono definite in questo modo:

        <toolkit:DataGrid.Columns>
            <toolkit:DataGridTemplateColumn Header="" MinWidth="35" MaxWidth="35" SortMemberPath="Position.PositionIndex" CanUserSort="True">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Path=Position}"/>
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
            </toolkit:DataGridTemplateColumn>
            <toolkit:DataGridTemplateColumn Header="Name" MinWidth="150" Width="150" SortMemberPath="Name" CanUserSort="True">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Path=Name}"/>
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
            </toolkit:DataGridTemplateColumn>
            <toolkit:DataGridTemplateColumn Header="Data" Width="Auto" CanUserSort="False">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Path=Data}"/>
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
            </toolkit:DataGridTemplateColumn>
        </toolkit:DataGrid.Columns>

Quindi, poiché le mie colonne Row e Name sono UserControls, il file WPF DataGrid non è possibile ordinarli in modo nativo.Quindi, per facilitare l'ordinamento, quando si fa clic sull'intestazione di una colonna, ne faccio alcune ListCollectionView.CustomSort Magia.

Ecco come appaiono i miei selezionatori personalizzati per la colonna Nome:

// Customized sorter, by name, ascending.
public class AscendingNameSorter : IComparer
{
    public int Compare(object x, object y)
    {
        var lhs = (MyViewModel)x;
        var rhs = (MyViewModel)y;

        return lhs.Name.CompareTo(rhs.Name);
    }
}

// Customized sorter, by name, descending.
public class DescendingNameSorter : IComparer
{
    public int Compare(object x, object y)
    {
        var lhs = (MyViewModel)x;
        var rhs = (MyViewModel)y;

        return rhs.Name.CompareTo(lhs.Name);
    }
}

Il problema è che è così incredibilmente lento.Non riesco a capire perché.Con 10 articoli nel DataGrid, la mia applicazione si blocca per 3-4 secondi mentre ricorre.ho pensato ListCollectionView.CustomSort doveva essere il modo più efficiente per ordinare un file ObservableCollection...dove sbaglio?

È stato utile?

Soluzione

WPF ricrea tutti i tuoi controlli utente ogni volta che l'ordinamento cambia, quindi suppongo che qualcosa nella costruzione di tali controlli sia lento.Ma questa è solo una supposizione.

Dovresti iniziare restringendo il problema.Ecco alcuni passaggi che puoi eseguire:

  1. Scopri quale operazione richiede 3-4 secondi.Non hai indicato se il ritardo si verifica solo quando si assegna il valore a CustomSort o ogni volta che l'elenco cambia dopo che CustomSort è stato impostato.Questo fa la differenza.

  2. Prova ad aggiungere una colonna di testo normale e ad ordinarla utilizzando l'ordinamento integrato per vedere se è veloce o meno.Forse l'hai già fatto, ma non l'hai detto nella tua domanda.

  3. Per scopi diagnostici, interrompere temporaneamente l'impostazione CustomSort e impostare invece ListCollectionView.Filter.Impostalo su un filtro che restituisca sempre true.Se il rallentamento persiste, il problema è legato al tentativo di ListCollectionView di riorganizzare gli elementi.

  4. Modifica temporaneamente i tuoi modelli e sostituisci i tuoi controlli utente personalizzati con qualcosa di banale (ad es <CheckBox/>) per vedere se le cose accelerano o meno.

  5. Imposta i punti di interruzione nei costruttori dei tuoi UserControl per vedere se vengono chiamati il ​​numero di volte previsto (ad esempio 10 chiamate al costruttore se ci sono 10 elementi nell'elenco).Se vengono chiamati più volte del previsto, guarda le analisi dello stack per vedere da dove provengono le chiamate extra.

  6. Aggiungi codice ai costruttori UserControl per scrivere DateTime. Ora i costruttori sono stati chiamati nella finestra di output (o in un registro o altro).Questo ti darà un'idea di quanto tempo impiega ciascuno.

  7. Aggiungi diverse centinaia di elementi alla tua ObservableCollection, esegui la tua app fianco a fianco con VS.NET, fai clic sul pulsante di ordinamento (o qualsiasi altra cosa), quindi premi il pulsante Interrompi tutto in VS.NET e osserva l'analisi dello stack.Premi Continua e premi immediatamente di nuovo Interrompi tutto, quindi osserva nuovamente l'analisi dello stack.Ripeti molte volte.Questo ti darà una buona idea di cosa richiede tutto il tempo extra.

Se, come sospetto, il problema è la lentezza nella creazione e nell'associazione degli UserControls, troverai:Il problema si verifica ad ogni modifica dell'elenco e si verifica anche quando si modifica il filtro, le cose accelerano quando si sostituiscono i controlli utente con <CheckBox/>, il tuo costruttore verrà chiamato solo una volta per elemento, il tempo tra le chiamate sarà lungo.

Nota che non sto dicendo che sia il costruttore degli UserControl che è lento: è possibile che UserControl crei un'istanza di molti oggetti secondari quando è associato a dati o che includa oggetti lenti o complessi, un oggetto secondario carichi un file o molte altre possibili cause.La conclusione è che creare un'istanza di DataTemplate sull'oggetto e aggiungerlo all'albero visivo sta facendo qualcosa di lento.Le analisi dello stack dovrebbero darti un'idea di dove cercare.

Se si scopre che si tratta di qualcos'altro o non riesci a capirlo, aggiorna semplicemente la tua domanda per fornire maggiori informazioni su ciò che hanno rivelato i test di cui sopra e cercheremo di aiutarti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top