8

現在、次の機能を模倣した2つのWPFリストボックスがあります。

Word2007のカスタマイズ画面
(出典:psu.edu

私は2つのObservableCollectionsを使用して、ユーザーが必要なアイテムを選択できるようにしています(ここでは柔軟性が重要です)。主な問題は、両方のリストボックスにグループ化された何千ものアイテムがあることです。全体として、デザインは非常にうまく機能します(数十のアイテムがあります)が、画面がフリーズしたときにユーザーが利用可能なすべてのアイテムを左から右にコピーするときに障害が発生します(別のスレッドで実行する時間ですか?)。

ObservableCollectionを見ると、AddRangeメソッドがなく、インターネット上でさまざまな実装が利用可能です。また、各アイテムがパフォーマンスの低下にひどくコピーされるため、CollectionChangedイベントが不必要に発生していることも知っています。

将来的には、ユーザーが10,000を超えるアイテムのグループから選択できるようにする必要があるかもしれません。これは悪い考えのように聞こえますが、リストボックス(CollectionViewSource)でのグループ化は非常にうまく機能するため、交渉できません。両方のリストボックスの仮想化をオフにした場合の副作用

ObservableCollectionにデータバインドされたときに何千ものアイテムを含むリストボックスをロードするときのパフォーマンスを向上させるために何ができますか?推奨するAddRangeタイプの実装はありますか?データベースからデータをロードしていないため、コストがかかると思われるバックグラウンドスレッドでこれを実行するための唯一の選択肢はありますか?

4

4 に答える 4

2

CollectionViewSource とグループ化を削除しました。アイテムは 1/2 秒でコピーされますが、仮想化がグループ化で機能しないため、グループ化すると最大 1 分かかる場合があります。

CollectionViewSource を使用するかどうかを決定する必要があります

于 2009-09-09T10:48:45.600 に答える
2

私はこれに答えざるを得ませんでした。この回答はもう必要ないと思いますが、他の誰かが使用できるかもしれません。

あまり難しく考えないでください (このマルチスレッドにアプローチしないでください (これによりエラーが発生しやすくなり、不必要に複雑になります。難しい計算/IO にのみスレッドを使用してください)、これらすべての異なるアクションタイプにより、バッファリングが非常に困難になります。最も厄介な部分つまり、10000 個の項目を削除または追加すると、アプリケーション (リストボックス) は、ObservableCollection によって発生したイベントの処理で非常に忙しくなります. イベントは既に複数の項目をサポートしています. そう.....

アクションが変更されるまで、アイテムをバッファできます。そのため、「ユーザー」がアクションを変更またはフラッシュすると、追加アクションはバッファリングされ、バッチとして発生します。テストしていませんが、次のようなことができます。

// Written by JvanLangen
public class BufferedObservableCollection<T> : ObservableCollection<T>
{
    // the last action used
    public NotifyCollectionChangedAction? _lastAction = null;
    // the items to be buffered
    public List<T> _itemBuffer = new List<T>();

    // constructor registeres on the CollectionChanged
    public BufferedObservableCollection()
    {
        base.CollectionChanged += new NotifyCollectionChangedEventHandler(ObservableCollectionUpdate_CollectionChanged);
    }

    // When the collection changes, buffer the actions until the 'user' changes action or flushes it.
    // This will batch add and remove actions.
    private void ObservableCollectionUpdate_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // if we have a lastaction, check if it is changed and should be flush else only change the lastaction
        if (_lastAction.HasValue)
        {
            if (_lastAction != e.Action)
            {
                Flush();
                _lastAction = e.Action;
            }
        }
        else
            _lastAction = e.Action;

        _itemBuffer.AddRange(e.NewItems.Cast<T>());
    }

    // Raise the new event.
    protected void RaiseCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (this.CollectionChanged != null)
            CollectionChanged(sender, e);
    }

    // Don't forget to flush the list when your ready with your action or else the last actions will not be 'raised'
    public void Flush()
    {
        if (_lastAction.HasValue && (_itemBuffer.Count > 0))
        {
            RaiseCollectionChanged(this, new NotifyCollectionChangedEventArgs(_lastAction.Value, _itemBuffer));
            _itemBuffer.Clear();
            _lastAction = null;
        }
    }

    // new event
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
}

楽しんでね、J3R03N

于 2011-12-22T23:41:33.263 に答える
1

おそらく から継承ObservableCollection<T>(または直接実装) して、メソッドINotifyCollectionChangedを追加できます。との呼び出しの間に行われた変更はキューに入れられ、が呼び出されたときにイベントのハンドラーに渡される 1 つ (または別の範囲がある場合は複数) のオブジェクトに結合されます。BeginUpdateEndUpdateBeginUpdateEndUpdateNotifyCollectionChangedEventArgsCollectionChangedEndUpdate

于 2009-09-09T09:38:52.450 に答える
1

スレッド セーフなオブザーバブル コレクションはこちらにあります。Observable コレクションをスレッドセーフにして、リストボックスにバインドします。

于 2009-09-09T09:42:58.473 に答える