Question

J'ai un ObservableCollection de ViewModels qui sont assis dans un DataGrid WPF. Le DataGrid a trois colonnes:

  • colonne de position; Ceci est rendu à l'exécution par un UserControl qui affiche la position de la ligne dans mon DataGrid
  • colonne Nom; Ceci est rendu à l'exécution par un UserControl qui affiche le nom de la colonne (oui, je besoin d'un UserControl pour cette fonction sur la façon dont le nom doit être affiché, mais qui est un aparté)
  • colonne de données; Ceci est rendu à l'exécution par un autre UserControl.

Mes colonnes sont définies comme suit:

        <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>

Alors, parce que mes colonnes de lignes et de nom sont UserControls, le DataGrid WPF ne peut pas nativement tri sur eux. Donc, pour faciliter le tri, quand un en-tête de colonne est cliqué, je fais un peu de magie ListCollectionView.CustomSort.

Voici ce que mes trieurs personnalisés ressemblent pour la colonne Nom:

// 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);
    }
}

Le problème est que cela est incroyablement lent . Je ne peux pas comprendre pourquoi. Avec 10 articles dans la DataGrid, ma demande enraye pendant 3-4 secondes alors qu'il recourt. Je pensais que ListCollectionView.CustomSort était censé être le moyen le plus efficace pour trier un ObservableCollection ... où vais-je tort?

Était-ce utile?

La solution

WPF recrée tous vos UserControls chaque fois que les changements de tri, donc je suppose que quelque chose dans la construction de ces contrôles est lent. Mais ce n'est une supposition.

Vous devriez commencer par réduire le problème. Voici quelques mesures que vous pouvez prendre:

  1. En savoir quelle opération prend 3-4 secondes. Vous n'avez pas dit si le retard ne se produit que lors de l'attribution de la valeur à CustomSort, ou chaque fois que les modifications de la liste après CustomSort a été défini. Cela fait une différence.

  2. Essayez d'ajouter une colonne de texte normal et le tri sur l'aide du genre intégré pour voir si elle est rapide ou non. Peut-être que vous avez déjà fait cela, mais vous ne l'avez pas dit dans votre question.

  3. Pour des fins de diagnostic arrêter temporairement la mise en CustomSort et mis en place ListCollectionView.Filter. Réglez-le sur un filtre qui retourne toujours vrai. Si vous obtenez toujours le ralentissement, le problème est lié à la tentative de ListCollectionView de réorganiser les éléments.

  4. modifier temporairement vos modèles et remplacer vos UserControls personnalisés avec quelque chose de trivial (par exemple <CheckBox/>) pour voir si les choses accélèrent ou non.

  5. Définir des points d'arrêt dans les constructeurs de votre UserControls pour voir si elles sont appelées le nombre prévu de fois (soit 10 constructeur appelle s'il y a 10 éléments dans la liste). Si elles sont appelées plusieurs fois que prévu, regardez la pile des traces pour voir où les appels supplémentaires viennent.

  6. Ajoutez le code à vos constructeurs UserControl pour écrire le DateTime.Now les constructeurs ont été appelés à la fenêtre de sortie (ou un journal, ou autre). Cela vous donnera une idée combien de temps chacun prend.

  7. Ajouter plusieurs centaines d'articles à votre ObservableCollection, exécutez votre côte à côte avec application VS.NET, cliquez sur le bouton de tri (ou autre), puis appuyez sur la touche Break All en VS.NET et regarder le trace de la pile. Appuyez sur Continuer et immédiatement hit Break All de nouveau, puis regardez la trace de la pile à nouveau. Répétez plusieurs fois. Cela vous donnera une bonne idée de ce qui se passe tout le temps supplémentaire.

Si, comme je le soupçonne, le problème est la création de UserControls lent et contraignant, vous trouverez: Le problème se produit à chaque changement de liste et se produit également lorsque vous changez le filtre, les choses accélèrent lorsque vous remplacez vos UserControls avec <CheckBox/>, votre constructeur ne sera appelé une fois par article, le temps entre les appels sera assez grande.

Notez que je ne dis pas que c'est le constructeur des UserControls qui est lent - il se pourrait que l'UserControl instancie plusieurs sous-objets quand il est lié aux données, ou qu'il comprend des objets qui sont lents ou complexes, un sous-objet charge un fichier, ou bien d'autres causes possibles. L'essentiel est que l'instanciation DataTemplate sur l'objet et l'ajouter à l'arbre visuel est en train de faire quelque chose de lent. Les traces de la pile devrait vous donner une idée où chercher.

S'il se avère être quelque chose d'autre ou vous ne pouvez pas le comprendre, il suffit de mettre à jour votre question pour donner plus d'informations sur ce que les tests ci-dessus ont révélé, et nous allons essayer de vous aider.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top