我有ObservableCollection
个ViewModel,它们位于WPF DataGrid
中。 DataGrid
有三列:
我的列定义如下:
<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);
}
}
问题是非常慢。我无法弄清楚为什么。在DataGrid
中有10个项目,我的应用程序在停靠时会停止3-4秒。我认为ListCollectionView.CustomSort
应该是对ObservableCollection
进行排序的最有效方式......我哪里出错?
答案 0 :(得分:3)
每次排序更改时,WPF都会重新创建所有UserControl,因此我猜测构建这些控件的速度很慢。但这只是猜测。
您应该首先缩小问题范围。您可以采取以下步骤:
找出需要3-4秒的操作。您没有说明是否仅在将值分配给CustomSort时发生延迟,或者每次在设置CustomSort后列表发生更改时都会发生延迟。这有所不同。
尝试添加常规文本列并使用内置排序对其进行排序,以查看它是否快速。也许你已经这样做了,但你没有在你的问题中说。
出于诊断目的,暂时停止设置CustomSort并改为设置ListCollectionView.Filter。将其设置为始终返回true的过滤器。如果仍然出现减速,则问题与ListCollectionView尝试重新组织项目有关。
暂时编辑模板,并用微不足道的内容(例如<CheckBox/>
)替换自定义UserControl,以查看是否加速。
在UserControls的构造函数中设置断点,以查看它们是否被调用了预期的次数(即如果列表中有10个项目,则为10个构造函数调用)。如果他们被调用的次数超过预期,请查看堆栈跟踪以查看额外呼叫的来源。
向UserControl构造函数添加代码以编写DateTime.Now构造函数被调用到输出窗口(或日志,或其他)。这会让你知道每个人花多长时间。
向ObservableCollection添加数百个项目,与VS.NET并排运行您的应用程序,单击您的排序按钮(或其他),然后点击VS.NET中的Break All按钮并查看堆栈跟踪。点击继续并立即再次点击Break All,然后再次查看堆栈跟踪。重复多次。这将使您更好地了解所有额外时间。
如果我怀疑问题是UserControls的创建和绑定速度慢,你会发现:每次更改列表时都会出现问题,当你更改过滤器时也会发生这种情况,当你用{{1替换你的UserControls时,事情会加快,每个项目只会调用一次构造函数,调用之间的时间间隔会很大。
请注意,我并不是说UserControls的构造函数很慢 - 可能是UserControl在数据绑定时实例化了许多子对象,或者它包括缓慢或复杂的对象,子对象加载文件或许多其他可能的原因。底线是在对象上实例化DataTemplate并将其添加到可视化树中是做得很慢。堆栈跟踪应该让您知道在哪里查看。
如果结果是其他内容或者您无法解决问题,只需更新您的问题以提供有关上述测试结果的更多信息,我们将尽力帮助您。