Почему ListCollectionView.CustomSort такой медленный? - PullRequest
1 голос
/ 08 января 2010

У меня есть ObservableCollection ViewModels, которые сидят в WPF DataGrid. DataGrid имеет три столбца:

  • Положение столбца; это отображается во время выполнения UserControl, который отображает положение строки в моей DataGrid
  • Имя столбца; это отображается во время выполнения с помощью UserControl, который отображает имя столбца (да, мне нужен UserControl для этого на основе того, как должно отображаться имя, но это не так)
  • столбец данных; это выполняется во время выполнения еще одним UserControl.

Мои столбцы определены так:

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

Итак, поскольку мои столбцы Row и Name являются UserControls, WPF DataGrid не может сортировать по ним. Поэтому, чтобы упростить сортировку, когда щелкают заголовок столбца, я делаю магию ListCollectionView.CustomSort.

Вот как выглядят мои пользовательские сортировщики для столбца Имя:

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

Проблема в том, что это невероятно медленно . Я не могу понять, почему. С 10 пунктами в DataGrid мое приложение останавливается на 3-4 секунды, пока оно перерабатывается. Я думал, что ListCollectionView.CustomSort должен был быть самым эффективным способом сортировки ObservableCollection ... где я ошибаюсь?

1 Ответ

3 голосов
/ 08 января 2010

WPF воссоздает все ваши UserControls каждый раз, когда изменяется сортировка, поэтому я предполагаю, что что-то в создании этих элементов управления идет медленно. Но это только предположение.

Вы должны начать с сужения проблемы. Вот несколько шагов, которые вы можете предпринять:

  1. Узнайте, какая операция занимает 3-4 секунды. Вы не указали, происходит ли задержка только при назначении значения пользовательской сортировке или каждый раз, когда список изменяется после установки пользовательской сортировки. Это имеет значение.

  2. Попробуйте добавить обычный текстовый столбец и отсортировать по нему, используя встроенную сортировку, чтобы увидеть, быстро это или нет. Возможно, вы уже сделали это, но вы не сказали в своем вопросе.

  3. В целях диагностики временно остановите настройку CustomSort и установите вместо нее ListCollectionView.Filter. Установите для него фильтр, который всегда возвращает true. Если вы все еще получаете замедление, проблема связана с попыткой ListCollectionView реорганизовать элементы.

  4. Временно отредактируйте ваши шаблоны и замените пользовательские элементы управления UserControl чем-то тривиальным (например, <CheckBox/>), чтобы увидеть, ускоряется ли ситуация.

  5. Установите точки останова в конструкторах ваших UserControls, чтобы увидеть, вызывается ли их ожидаемое количество раз (т.е. 10 вызовов конструктора, если в списке 10 элементов). Если их вызывают больше раз, чем ожидалось, посмотрите на трассировку стека, чтобы увидеть, откуда поступают дополнительные вызовы.

  6. Добавьте код в ваши конструкторы UserControl для записи DateTime. Теперь конструкторы были вызваны в окно вывода (или журнал, или что-то еще). Это даст вам некоторое представление о том, сколько времени занимает каждый.

  7. Добавьте несколько сотен элементов в ObservableCollection, запустите ваше приложение бок о бок с VS.NET, нажмите кнопку сортировки (или любую другую), затем нажмите кнопку «Разбить все» в VS.NET и посмотрите на трассировки стека. Нажмите «Продолжить» и немедленно нажмите «Разбить все», затем снова посмотрите на трассировку стека Повторите много раз. Это даст вам хорошее представление о том, что занимает все дополнительное время.

Если, как я подозреваю, проблема заключается в медленном создании и привязке UserControls, вы обнаружите: проблема возникает при каждом изменении списка, а также происходит при смене фильтра, вещи ускоряются при замене пользовательских контроллеров на <CheckBox/> ваш конструктор будет вызываться только один раз для каждого элемента, время между вызовами будет большим.

Обратите внимание, что я не говорю, что это конструктор UserControls, который работает медленно - возможно, что UserControl создает множество дочерних объектов, когда он связан с данными, или что он включает объекты которые являются медленными или сложными, подобъект загружает файл или множество других возможных причин. Суть в том, что создание экземпляра DataTemplate объекта и добавление его в визуальное дерево делает что-то медленное. Следы стека должны дать вам представление, где искать.

Если это окажется чем-то другим или вы не можете понять это, просто обновите свой вопрос, чтобы дать больше информации о том, что показали вышеуказанные тесты, и мы постараемся вам помочь.

...