(ObservableCollectionを使用する代わりに)INotifyCollectionChangedを明示的に実装することで、これを機能させました。さらに、Updateアクションを使用すると、同じ「サポートされていない」エラーが発生しましたが、AddアクションとRemoveアクションを使用できることがわかりました。したがって、私のスワップ関数は次のようになります。
class MyCollection<T> : List<T>, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void swap( int i, int j )
{
T a = this[i];
T b = this[j];
// swap my own internal data storage
this[i] = b;
this[j] = a;
// and also let my CollectionChanged listener know that I have done so.
if( CollectionChanged != null )
{
NotifyCollectionChangedEventArgs arg;
arg = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove, a, i );
CollectionChanged( this, arg );
arg = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, b, i );
CollectionChanged( this, arg );
arg = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove, b, j );
CollectionChanged( this, arg );
arg = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, a, j );
CollectionChanged( this, arg );
}
}
}
動的な変更はかなりローカルであるため、幸いなことに、変更に応じてより遅い手書きの並べ替えを使用することは、私にとっては問題なく機能しています。つまり、更新が到着すると、次のような別のメンバー関数(同じコレクション内)を呼び出します。
public void ProcessUpdates( List<T> updateList )
{
// use the contents of updateList to modify my internal store
// ...
// and now resort myself
sort();
}
private void sort()
{
// implement your favorite stable sorting algorithm here, calling
// swap() whenever you swap two elements.
// (this is an intentionally facetious sorting algorithm, because I
// don't want to get into the long and irrelevant details of my own
// data storage.)
while( i_am_not_sorted() )
{
int i = random_index();
int j = random_index();
if( out_of_order(i,j) )
{
// modify my internal data structure and
// also let my CollectionChanged listener know that I have done so
swap( i, j );
}
}
}
コレクションに要素を追加するときに「追加」通知を発行する必要があることも忘れないでください。最初のリストを並べ替えてから、並べ替えた順序で追加します。これにより、最初にデータを入力するときに、より効率的なライブラリ並べ替えを使用できます。