Почему ListCollectionView.CustomSort работает так медленно?
-
19-09-2019 - |
Вопрос
У меня есть ObservableCollection
из ViewModels , которые находятся в WPF DataGrid
.В DataGrid
имеет три столбца:
- Столбец положения;это отображается во время выполнения с помощью пользовательского элемента управления, который отображает положение строки в моей таблице данных
- Столбец имени;это отображается во время выполнения с помощью пользовательского элемента управления, который отображает имя столбца (да, мне нужен пользовательский элемент управления для этого, основанный на том, как должно отображаться имя, но это в стороне)
- Столбец данных;это отображается во время выполнения еще одним 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 воссоздает все ваши пользовательские элементы управления каждый раз, когда меняется сортировка, поэтому я предполагаю, что что-то в построении этих элементов управления происходит медленно.Но это всего лишь предположение.
Вам следует начать с сужения круга проблем.Вот несколько шагов, которые вы можете предпринять:
Выясните, какая операция занимает 3-4 секунды.Вы не указали, происходит ли задержка только при присвоении значения CustomSort или каждый раз, когда список изменяется после установки CustomSort.Это имеет значение.
Попробуйте добавить обычный текстовый столбец и выполнить сортировку по нему с помощью встроенной сортировки, чтобы увидеть, выполняется ли это быстро или нет.Возможно, вы уже делали это, но вы не сказали об этом в своем вопросе.
В целях диагностики временно остановите настройку CustomSort и установите ListCollectionView.Вместо этого выполните фильтрацию.Установите для него фильтр, который всегда возвращает значение true.Если вы все еще испытываете замедление, проблема связана с попыткой ListCollectionView реорганизовать элементы.
Временно отредактируйте ваши шаблоны и замените ваши пользовательские элементы управления чем-нибудь тривиальным (например
<CheckBox/>
) чтобы посмотреть, ускорится ли процесс или нет.Установите точки останова в конструкторах вашего UserControls, чтобы увидеть, вызываются ли они ожидаемое количество раз (т. Е. 10 вызовов конструктора, если в списке 10 элементов).Если они вызываются больше раз, чем ожидалось, посмотрите на трассировки стека, чтобы увидеть, откуда поступают дополнительные вызовы.
Добавьте код в свои конструкторы UserControl для записи даты и времени.Теперь конструкторы были вызваны в окно вывода (или журнал, или что-то еще).Это даст вам некоторое представление о том, сколько времени занимает каждый из них.
Добавьте несколько сотен элементов в свою ObservableCollection, запустите свое приложение параллельно с VS.NET, нажмите кнопку сортировки (или любую другую), затем нажмите кнопку Разбить все в VS.NET и посмотрите на трассировку стека.Нажмите Продолжить и сразу же снова нажмите Разбить все, затем снова просмотрите трассировку стека.Повторите много раз.Это даст вам хорошее представление о том, на что уходит все дополнительное время.
Если, как я подозреваю, проблема заключается в медленном создании и привязке UserControls, вы обнаружите:Проблема возникает при каждом изменении списка, а также возникает при смене фильтра, все ускоряется, когда вы заменяете свои пользовательские элементы управления на <CheckBox/>
, ваш конструктор будет вызываться только один раз для каждого элемента, время между вызовами будет большим.
Обратите внимание, что я не говорю, что это конструктор из медленных пользовательских элементов управления - это может быть связано с тем, что пользовательский элемент управления создает множество подобъектов, когда он привязан к данным, или что он включает медленные или сложные объекты, подобъект загружает файл или по многим другим возможным причинам.Суть в том, что создание экземпляра DataTemplate для объекта и добавление его в визуальное дерево выполняется медленно.Трассировки стека должны дать вам представление о том, где искать.
Если окажется, что это что-то другое или вы не можете в этом разобраться, просто обновите свой вопрос, чтобы предоставить больше информации о том, что показали вышеуказанные тесты, и мы постараемся вам помочь.