1

私はObservableCollectionWPF に座っている ViewModelsを持っていDataGridます。には次のDataGrid3 つの列があります。

  • 位置列; これは、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>

したがって、行と名前の列は UserControls であるため、WPFDataGridはそれらをネイティブに並べ替えることができません。そのため、並べ替えを容易にするために、列ヘッダーがクリックされたときに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...どこが間違っていますか?

4

1 に答える 1

3

WPF は、並べ替えが変更されるたびにすべての UserControls を再作成しているため、これらのコントロールの構築に何か問題があると思います。しかし、それは推測にすぎません。

問題を絞り込むことから始めるべきです。次の手順を実行できます。

  1. どの操作に 3 ~ 4 秒かかっているかを調べます。CustomSort に値を代入するときだけ遅延が発生するのか、それとも CustomSort が設定された後にリストが変更されるたびに遅延が発生するのかについては述べていません。これは違いを生みます。

  2. 通常のテキスト列を追加し、組み込みの並べ替えを使用して並べ替えて、高速かどうかを確認してください。おそらくあなたはすでにこれを行っていますが、あなたの質問では言いませんでした.

  3. 診断目的で、CustomSort の設定を一時的に停止し、代わりに ListCollectionView.Filter を設定します。常に true を返すフィルターに設定します。それでも速度が低下する場合、問題は ListCollectionView がアイテムを再編成しようとしたことに関連しています。

  4. テンプレートを一時的に編集し、カスタム UserControls を単純なもの (例: <CheckBox/>) に置き換えて、速度が上がるかどうかを確認します。

  5. UserControls のコンストラクターにブレークポイントを設定して、予想される回数 (リストに 10 個の項目がある場合は 10 個のコンストラクター呼び出し) で呼び出されているかどうかを確認します。それらが予想よりも多く呼び出されている場合は、スタック トレースを調べて、余分な呼び出しがどこから来ているかを確認します。

  6. UserControl コンストラクターにコードを追加して、DateTime を書き込みます。これで、コンストラクターが出力ウィンドウ (またはログなど) に呼び出されました。これにより、それぞれにかかる時間がわかります。

  7. ObservableCollection に数百のアイテムを追加し、アプリを VS.NET と並べて実行し、並べ替えボタン (またはその他のもの) をクリックしてから、VS.NET の [Break All] ボタンをクリックして、スタック トレースを確認します。[Continue] をクリックしてすぐに [Break All] をもう一度押してから、スタック トレースをもう一度見てください。何度も繰り返します。これにより、何が余分な時間を取っているかがよくわかります。

私が推測するように、問題が UserControls の作成とバインディングの遅さである場合、次のことがわかります。問題はリストの変更ごとに発生し、フィルターを変更したときにも発生します。UserControls を に置き換えると速度が上がり<CheckBox/>、コンストラクターはアイテムごとに 1 回呼び出されると、呼び出し間の時間が長くなります。

UserControlsのコンストラクターが遅いと言っているわけではないことに注意してください。UserControl がデータ バインドされている場合に多くのサブオブジェクトをインスタンス化するか、低速または複雑なオブジェクトが含まれている場合、サブオブジェクトが読み込まれる可能性があります。ファイル、または他の多くの考えられる原因。肝心なのは、オブジェクトで DataTemplate をインスタンス化し、それをビジュアル ツリーに追加すると、何かが遅くなるということです。スタック トレースから、どこを見ればよいかがわかります。

それが何か他のものであることが判明した場合、またはそれを理解できない場合は、質問を更新して、上記のテストで明らかになったことに関する詳細情報を提供してください。私たちはあなたを助けようとします.

于 2010-01-08T20:40:00.250 に答える