Почему ListCollectionView.CustomSort работает так медленно?

StackOverflow https://stackoverflow.com/questions/2028835

  •  19-09-2019
  •  | 
  •  

Вопрос

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

  • Столбец положения;это отображается во время выполнения с помощью пользовательского элемента управления, который отображает положение строки в моей таблице данных
  • Столбец имени;это отображается во время выполнения с помощью пользовательского элемента управления, который отображает имя столбца (да, мне нужен пользовательский элемент управления для этого, основанный на том, как должно отображаться имя, но это в стороне)
  • Столбец данных;это отображается во время выполнения еще одним 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 Магия.

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

// 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...где я иду не так, как надо?

Это было полезно?

Решение

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top