0

次のカスタム監視可能なコレクションがあります (コードは Dean Chalk のブログhttp://www.deanchalk.me.uk/post/Thread-Safe-Dispatcher-Safe-Observable-Collection-for-WPF.aspxおよびわずかに変更):

public class ThreadSaveObservableCollection <T> : IList<T>, INotifyCollectionChanged  {

    private IList<T> collection;
    private Dispatcher uiDispatcher;
    private ReaderWriterLock rwLock;

    public ThreadSaveObservableCollection () {

        collection = new List<T>();
        rwLock = new ReaderWriterLock();
        uiDispatcher = Dispatcher.CurrentDispatcher;
    }

    public void Insert (int index, T item) {

        if (Thread.CurrentThread == uiDispatcher.Thread) {

            insert_(index, item);
        } else {

            uiDispatcher.BeginInvoke(new Action<int, T>(insert_), DispatcherPriority.Normal, new object[] {index, item});
        }
    }

    private void insert_ (int index, T item) {

        rwLock.AcquireWriterLock(Timeout.Infinite);

        collection.Insert(index, item);
        CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));

        rwLock.ReleaseWriterLock();
    }

    public IEnumerator<T> GetEnumerator () {

        rwLock.AcquireReaderLock(Timeout.Infinite);

        IEnumerator<T> enumerator = collection.GetEnumerator();

        rwLock.ReleaseReaderLock();

        return enumerator;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {

        rwLock.AcquireReaderLock(Timeout.Infinite);

        IEnumerator<T> enumerator = collection.GetEnumerator();

        rwLock.ReleaseReaderLock();

        return enumerator;
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    ... // the remaining methods of the IList<> interface

}

さらに、このクラスのインスタンスを保持する ViewModel があります。

public class ViewModel {

    private ThreadSaveObservableCollection<string> Collection {get; set;}

    public ViewModel () {
        Collection = new ThreadSaveObservableCollection<string>();
    }

    public void Insert (string item) {

        Collection.Insert(0, item);
    }

}

「LogList」という名前の対応する WPF コントロール (通常のリスト コントロール) を動的に作成するため、コード ビハインドでデータ バインディングを適用します。

wpfContainer.LogList.ItemsSource = viewModel.Collection;

wpf リスト コントロール内の項目の順序が、ViewModel の Collection オブジェクト内の項目に対して逆になっているという事実を除いて、すべてが正常に機能します。

ステートメント Collection.Insert(0, intem) を使用すると、リストの一番上に新しいアイテムを追加することが期待されますが、Collection.Add(item) を使用した場合と同じ結果が得られます。

実行時にコードにステップインすると、コレクション内のアイテムが正しい順序になっていることを確認できますが、wpf リスト コントロール内の表面では順序が変更されています。つまり、逆になっています。

私は何を間違えていますか?

私のObservableCollectionをwpfコントロールに接続するのは「ワイヤ」であり、正しい順序がワイヤに入り、間違った順序がワイヤを離れているように見えるため、問題はデータバインディングのどこかにあるはずだと思います。

wpf コントロールの ItemSource プロパティが Enumerator を待っているため、IList インターフェイスの GetEnumerator() メソッドと関係があるのでしょうか。

私には手がかりがなく、本当に立ち往生しています...

助けてくれてありがとう...

4

2 に答える 2

1

これを試してみることができますか:

http://msdn.microsoft.com/en-us/library/ms653208.aspx

CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<object>() { item }, 0));

この事件が問題だと思います。

于 2012-06-07T21:55:42.410 に答える
1

コードに関するいくつかのメモ:

  • ネーミング: ThreadSave ではなく ThreadSafe
  • 競合状態: .GetEnumerator を呼び出すためのロックを取得しています。次に、ロックを解放し、その列挙子を返します。これは安全ではなく、スレッドの条件が正しければ、実行時に例外がスローされます。ここですべきことは、ロックされている間にリストのコピーを作成し、そのコピーに列挙子を返すことです。
  • ReaderWriterLock には、既知のパフォーマンス、スケーラビリティ、およびエラーが発生しやすい使用方法 (再入力など) に関する懸念があります。代わりにReaderWriterLocksSlimを使用してください。
  • ここでの全体的な考え方は、すべての操作を UI スレッドにマーシャリングすることです。すべてが UI スレッドで発生する場合、ロックはまったく必要ありません。

最後に、車輪を再発明するのではなく、既存のスレッドセーフな ObservableCollectionsのいずれかを使用することをお勧めします。

于 2012-06-07T22:02:12.563 に答える