22

潜在的に数千のアイテム (3000 ~ 5000 と考えてください) がObservableCollection、いくつかのビジュアル インターフェイスにバインドされた に追加されるセットアップがあります。現在、それらを追加するプロセスは非常に遅く (約 4 秒/1000 項目)、もちろんその間 GUI は応答しません。システムのロックを心配せずに、一度に多くのアイテムをコレクションに移動するのに適した方法は何ですか? 私は見ましたDispatcherTimerが、必要なものがすべて提供されるかどうかはわかりません。

別の質問 - これらのオブジェクトをコレクションに追加するのにそれほど時間がかからないように、これらのオブジェクトの作成を高速化するためにできることはありますか? 現在、私はそれらを次のように使用しています:Collection.Add(new Item(<params>))おそらくバックグラウンドスレッドでアイテムを事前に生成すると、アイテムを追加するのにかかる時間が大幅に短縮されますか?

編集: 仮想化はできません。要件はWrapPanel外観を指定するため、表示は実際にはListBoxテンプレート化された ItemsPanel を持つ です

Edit2: ストップウォッチによると、ボトルネックは実際にアイテムを my に入れていObservableCollectionます。そのコレクション タイプを変更し、独自の通知を行って、大幅に高速化されるかどうかを確認します。

Edit3:したがって、答えは1か所にあります-から継承するクラスを作成することにより、(以下の助けを借りて)この問題を解決しましたObservableCollection。このクラスは 2 つのことを行いました。一度にコレクションを追加するメソッドを公開し、CollectionChangedイベントを抑制する機能を追加しました。これらの変更により、3000 個のアイテムを追加するのにかかる時間は約 0.4 秒です (97% の改善)。このリンクでは、これらの変更の実装について詳しく説明しています。

4

5 に答える 5

9

あなたは 1000 と言ったので、例としてその数に固執します。

IIRC では、監視可能なコレクションには小さな欠点があります。アイテムを 1 つずつ追加すると、アイテムごとに 1 回通知が発生します。つまり、1000 個のアイテムに対して 1000 個の通知があり、画面の再描画に追いつくためだけに UI スレッドが猛烈な速度で実行されます。

できるだけ早く再描画する必要がありますか? たぶん、追加をバッチ処理できますか?1000 個のアイテムを 100 個のアイテムのいくつかのパックに分割するか、50 個または 20 個のアイテムのもう少し多くのパケットに分割します。次に、すべてのアイテムを1つずつではなく、パケットに入れます。ただし、注意してください。LINQ ではなく、コレクション自体によって実装された AddRange などのメソッドを使用する必要があります。そうしないと、1 つずつ挿入することになります。このようなメソッドが見つかった場合、コレクションは AddRange 呼び出しごとに 1 回だけ Changed イベントを発生させる必要があるため、イベントの数を大幅に削減する必要があります。

監視可能なコレクションに AddRange がない場合、別のコレクションを使用するか、独自のコレクションを作成すると、おそらくラッパーだけで十分です。目標は、すべての Add() で Changed イベントを発生させないことですが、それらの適切な数の後、または - アイテムが追加されたときに Changed の発生をスキップして、一定の時間間隔で Changed を発生させますか? これは、データが一定の速度で無期限に「流入」する場合に特に有益です。

もちろん、その数のアイテムが画面に表示されると、それ自体をレンダリングすることで頭がいっぱいになるかもしれません。ItemTemplates が複雑な場合、ビジュアル レイヤー/プロパティのインスタンスの 1000 倍のオブジェクトの 1000 は、単純にユーザー エクスペリエンスを台無しにする可能性があります。ItemTemplates を最小限に簡素化しましたか?

最後に: 仮想化 StackPanels を ItemsControl/ListBoxes の ItemPanels として使用することを検討してください。メモリ フットプリントと一度に描画されるアイテムの数を大幅に削減できます。これは、発生するイベントの数や数に必ずしも役立つとは限りませんが、複雑なアイテム テンプレートがある場合は非常に役立つ場合があります。

編集:あなたはObservableCollectionを使用しているので、WPF/Silverlight..これが正しくない場合は質問を更新すると仮定しました

于 2012-08-14T18:33:48.833 に答える
8

Bindingこのため、WPFは同時実行をサポートしています。Binding.IsAsynctrue に設定してみてください。加えて。

  • を使用しないでくださいObservableCollection<T>。アイテムが追加されるたびにイベントが発生するため、これは低速です。すべてのアイテムが追加された後にList<T>プロパティの変更通知を発行するなど、より高速なものを使用してください。
  • バックグラウンド スレッドでアイテムを事前に作成してから、コレクションにプッシュします。
  • 関連するコードの他の部分をチェックして、膨張があるかどうかを確認し、トリムします。
于 2012-08-14T18:24:33.903 に答える
5

リクエストにより、この問題をどのように解決したかを次に示します。から継承するクラスを作成することから始めましたObservableCollection。このクラスは 2 つのことを行いました。一度にコレクション全体を追加するメソッドを公開し、CollectionChangedイベントを抑制する機能を追加しました。これらの変更により、3000 個のアイテムを追加するのにかかる時間は約 0.4 秒です (97% の改善)。このリンクでは、これらの変更の実装について詳しく説明しています。

于 2016-09-12T14:08:17.303 に答える
4

別の方法として、ObservableCollection をサブクラス化し、一括読み込み (AddRange) をサポートするようにします。ここに記事があります: AddRange と ObservableCollection

于 2012-08-14T19:19:47.133 に答える
0

GUIでWPFテクノロジを使用している場合の2番目の質問については、可視アイテムのみを作成できるVirualizingStackPanelを使用してパフォーマンスを向上させることができます

于 2012-08-14T18:30:35.387 に答える