2012-03-13 16 views
1

Silverlight 5.0を使用しており、IList<T>とIListを実装する必要があります。私のコレクションは、常に内部コレクションからアイテムを追加および削除するために使用され、UIにはコレクションにバインドされた要素があります。パフォーマンス上の理由から、コレクションに変更が加えられるたびにUIをレンダリングする必要はありません。コレクションの変更イベントを発生させる必要があります。また、すべてを非同期に保つためにTask.Factoryアプローチを使用してこれを実行できるようにしたいと考えています。誰もこれを達成するための良い例を見たことがありますか?非同期のスレッドセーフなコレクションINotifyCollectionChangedの実装

+1

Caliburn Microには、無効にすることができるIsNotifyingというプロパティを持つBindableコレクションがあります。私は、マルチスレッドの相互排除環境では使用していません。しかし、それは試してみる価値がある。 – Jeremiah

答えて

0

スレッドセーフで、観測可能なコレクションは、設計上問題があります。たとえば、コレクションを変更してイベントを発生させた場合、そのイベントの処理中に別のスレッドでコレクションを変更することができます。その結果、追加されたばかりのアイテムにすでに伝えられたハンドラは、すでに期限切れになっている可能性があります(アイテムはすでに削除されている可能性があります)。

また、コレクションが変更されたときにイベントでimmutable collectionを使用することを検討しましたか?これは本質的にスレッドセーフであり、正しく適用すると上記の設計上の問題を抱えません。このアプリの要件を満たしていない可能性があります。質問から分かりにくいです。

+0

ハンドラが期限切れになった後に呼び出されるという事実は、問題とはみなされません。ハンドラがそのようなことに対処することは難しいことではなく、適切に書かれたハンドラを用意するべきではありません。より大きな問題は、イベントハンドラがすでに実行されている間に何かがコレクションに追加される可能性があることです。通常、 'SomeCollection.Add'を呼び出すコードでは、すべてのイベントハンドラが復帰する前に起動されると仮定することができますが、そのようなセマンティクスを適用するとデッドロックが発生する可能性があります。 – supercat

0

私が提案するアプローチは、UIを更新する必要があるコレクションのさまざまな側面にさまざまなフラグを設定することです。コレクション内の何かが変更され、特定のフラグが設定されていない場合は、それを設定し、付属のコントロールおよびデリゲートにControl.BeginInvokeを使用します(Interlockedまたはロックを使用して、フラグのテストと設定がスレッドセーフな方法で行われるようにします) 。 UI更新メソッドは、更新を実行する前に適切なフラグをテストしてクリアする必要があります。更新が実行された場合、メソッドは更新を実行することなく完了するまですべてのフラグをループして再テストする必要があります。

このアプローチを使用すると、保留中の操作の数がBeginUpdateに達するのを避けることができます。いくつかの冗長なアップデートがあるかもしれませんが、一般的にはそれほど多くありません。場合によっては、コントロールのコードが1秒間に実行する更新の数を制限することが役立つ場合があります。更新ルーチンが頻繁に繰り返す場合は、タイマーを開始し、タイマーが切れるまで更新を無効にします。タイマーが切れて更新が必要な場合は、更新を実行してタイマーを再起動します。有効期限が切れ、更新が必要ない場合は、タイマーを停止します。

コレクションのすべての変更を「更新」イベントに反映しようとすると、非生産的になりがちです。コレクションの最後の変更後に表示の最後の更新が完全に行われることを確認してください。

関連する問題