【问题标题】:Why is ListCollectionView.CustomSort so slow?为什么 ListCollectionView.CustomSort 这么慢?
【发布时间】:2011-01-02 23:37:46
【问题描述】:

我有一个 ObservableCollection 的 ViewModels,它们位于 WPF DataGrid 中。 DataGrid 包含三列:

  • 位置栏;这是在运行时由一个显示行在我的 DataGrid 中的位置的 UserControl 呈现的
  • 名称列;这是在运行时由显示列名称的 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 进行排序的最有效方法...我哪里出错了?

【问题讨论】:

    标签: wpf sorting mvvm wpfdatagrid


    【解决方案1】:

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

    您应该从缩小问题范围开始。以下是您可以采取的一些步骤:

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

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

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

    4. 暂时编辑您的模板并用一些琐碎的东西(例如&lt;CheckBox/&gt;)替换您的自定义用户控件,看看事情是否加快了速度。

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

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

    7. 将数百个项目添加到您的 ObservableCollection,与 VS.NET 并行运行您的应用程序,单击排序按钮(或其他),然后单击 VS.NET 中的 Break All 按钮并查看堆栈跟踪。点击 Continue 并立即再次点击 Break All,然后再次查看堆栈跟踪。重复多次。这会让您清楚地知道是什么花费了所有额外的时间。

    如果我怀疑问题是 UserControls 创建和绑定缓慢,您会发现:问题发生在每次列表更改时,并且在您更改过滤器时也会发生,当您将 UserControls 替换为 &lt;CheckBox/&gt; 时,事情会加速,你的构造函数每个项目只会被调用一次,调用之间的时间会很长。

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

    如果结果是其他问题或者您无法弄清楚,只需更新您的问题以提供有关上述测试所揭示内容的更多信息,我们会尽力为您提供帮助。

    【讨论】:

    • 很好的回复,非常感谢 - 你的回答让我对这个问题有了几种不同的思考方式,我会尝试你的一些建议,让你知道它是怎么回事!谢谢!
    • 我很快尝试了 Checkbox 测试 - 不幸的是,它非常快。我会在星期一早上研究 UserControl 构造:-)
    • 好的,现在看起来是 UserControl 的构造阻止了排序,我可以做些什么来优化它?数据绑定是我呈现数据的重要组成部分,我不确定我能轻松做到这一点。
    • 我会尝试分析技术(反复点击 Break All 并查看堆栈跟踪)以查看真正慢的地方,然后对其进行优化。如果这种优化是不可能的,您可以将您的 ItemsSource 设置为您的数据的自定义视图模型,其中包括包含预先创建的 UserControls 的属性。在这种情况下,网格将简单地显示预先创建的用户控件而不是创建它们。
    猜你喜欢
    • 2021-09-03
    • 2016-09-28
    • 2020-02-08
    • 2012-07-17
    • 2011-11-07
    • 2015-08-24
    • 2013-08-06
    • 2014-07-16
    • 2019-06-16
    相关资源
    最近更新 更多