ObservableでSortedListなCollectionをつくってみた

やること

C#でWindowsアプリを開発するときによく用いるObservableCollectionで、SortedListみたいに常にソートされた状態でBindingに使いたい!ということがあったのでつくってみました。

ソース全体はこっち

SortedなObservableCollectionをつくる

実装する量が一番少なそうな方法を選びたかったので、ObservableCollection<T>を継承する方法を選択しました。
以下の手順で実装していきます。

  1. ObservableCollection<T>を継承するクラスの土台を作成
  2. ObservableCollection<T>のコンストラクタをコピペ
  3. 便利関数 FirstIndexOf(T), LastIndexOf(T) を実装 (4.で使うため)
  4. InsertItem(), MoveItem()をオーバーライド

ObservableCollection<T>は、AddやRemoveなどの操作をオーバーライドして好みのCollectionをつくることができます。便利ヾ(๑╹◡╹)ノ”

1. ObservableCollection\<T>を継承するクラスの作成

クラスObservableSortedCollection<T>をつくっていきます。
ソートできるようにするのが目的なので、TIComparable<T>を実装している前提にすることで、Collectionの実装を楽にできるようにします。

もし比較方法をいろいろ変えたい場合は、SortedListのようにComparerをプロパティとして持つように実装してもよいかもしれません。

今回は手軽さ重視。

2. ObservableSortedCollection\<T>のコンストラクタの実装

ObservableCollection<T>は2つのコンストラクタを持っています。

さっそく実装していきますが、2番目のコンストラクタの場合はソートによって順番が入れ替わる可能性があるため一つずつAddしていきます。

3. 便利関数 FirstIndexOf(T), LastIndexOf(T) の実装

あとあと、AddやMoveを実装する上でも必要となるIndexを取得する関数をつくっておきます。比較したときに同じ順位のオブジェクトが連続する可能性があるので、幅を持ったFirstとLastのIndexを取得できるようにしておきます。

また、IComparable<T>を使って手軽な実装をします。

IndexOf()nullも引数に取れるので便利。

4. InsertItem(),MoveItem()をオーバーライドしてSortedにする

今回は、追加と移動のときに適切な場所に挿入されるようにしていきます。(使わない引数は無視・・・)

ObservableCollection<T>ではこの他にも、SetItem(), RemoveItem(), ClearItem()をoverrideすることができます。

おまけ. Tのプロパティが変わって順番が入れ替わる場合

T.CompareTo()の中身によっては、プロパティを変えることで順番が変わってしまうと思います。上記の実装だと途中で変更があったときに順番が正しく入れ替わらないので、変更のときにうまく順番を入れ替えるようにします。

順番が入れ替わる可能性がある箇所に、Moveを入れていきます。

i. SetItem()のときに入れ替える

ii. INotifyPropertyChangedで変更をつかむ

Tのプロパティが変わったときにMoveが呼び出されるようにします。Tの条件にINotifyPropertyChangedも加えておきます。

PropertyChangedイベントに追加する関数を定義します。

InsertItem()でイベント変更通知関数を登録します。

RemoveItem(), ClearItems()でイベント変更通知関数を登録解除します。

SetItem()ではイベント変更通知関数を解除し、登録します。

おわりに

果たして楽な実装方法だったのか・・・

未分類

Posted by tanitanin


PAGE TOP