为什么ListCollectionView.CustomSort这么慢?

时间:2010-01-08 16:04:28

标签: wpf sorting mvvm wpfdatagrid

我有ObservableCollection个ViewModel,它们位于WPF DataGrid中。 DataGrid有三列:

  • 职位栏;这是在运行时由UserControl呈现的,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);
    }
}

问题是非常慢。我无法弄清楚为什么。在DataGrid中有10个项目,我的应用程序在停靠时会停止3-4秒。我认为ListCollectionView.CustomSort应该是对ObservableCollection进行排序的最有效方式......我哪里出错?

1 个答案:

答案 0 :(得分:3)

每次排序更改时,WPF都会重新创建所有UserControl,因此我猜测构建这些控件的速度很慢。但这只是猜测。

您应该首先缩小问题范围。您可以采取以下步骤:

  1. 找出需要3-4秒的操作。您没有说明是否仅在将值分配给CustomSort时发生延迟,或者每次在设置CustomSort后列表发生更改时都会发生延迟。这有所不同。

  2. 尝试添加常规文本列并使用内置排序对其进行排序,以查看它是否快速。也许你已经这样做了,但你没有在你的问题中说。

  3. 出于诊断目的,暂时停止设置CustomSort并改为设置ListCollectionView.Filter。将其设置为始终返回true的过滤器。如果仍然出现减速,则问题与ListCollectionView尝试重新组织项目有关。

  4. 暂时编辑模板,并用微不足道的内容(例如<CheckBox/>)替换自定义UserControl,以查看是否加速。

  5. 在UserControls的构造函数中设置断点,以查看它们是否被调用了预期的次数(即如果列表中有10个项目,则为10个构造函数调用)。如果他们被调用的次数超过预期,请查看堆栈跟踪以查看额外呼叫的来源。

  6. 向UserControl构造函数添加代码以编写DateTime.Now构造函数被调用到输出窗口(或日志,或其他)。这会让你知道每个人花多长时间。

  7. 向ObservableCollection添加数百个项目,与VS.NET并排运行您的应用程序,单击您的排序按钮(或其他),然后点击VS.NET中的Break All按钮并查看堆栈跟踪。点击继续并立即再次点击Break All,然后再次查看堆栈跟踪。重复多次。这将使您更好地了解所有额外时间。

  8. 如果我怀疑问题是UserControls的创建和绑定速度慢,你会发现:每次更改列表时都会出现问题,当你更改过滤器时也会发生这种情况,当你用{{1替换你的UserControls时,事情会加快,每个项目只会调用一次构造函数,调用之间的时间间隔会很大。

    请注意,我并不是说UserControls的构造函数很慢 - 可能是UserControl在数据绑定时实例化了许多子对象,或者它包括缓慢或复杂的对象,子对象加载文件或许多其他可能的原因。底线是在对象上实例化DataTemplate并将其添加到可视化树中是做得很慢。堆栈跟踪应该让您知道在哪里查看。

    如果结果是其他内容或者您无法解决问题,只需更新您的问题以提供有关上述测试结果的更多信息,我们将尽力帮助您。