2017年10月24日火曜日

ListView Extensions ver.1.0.0-beta2

最近久しぶりにWPFを触ったのですが、その中でListViewを使う機会がありました。

身近なListViewと言えばWindowsのエクスプローラーですが、例えばこれはヘッダーをクリックすることで思い思いの要素でファイルのソートができるのに対して、WPFのListViewにはそのような基本機能が備えられていません。
とは言っても、備えるのもかなりの根気がいる作業ですし、そもそも元のコレクションに介入する作業はPresentation Foundationと名の付くフレームワークがやるべきことではない気がします。

そこで、ListView Extensionsです。

MVVMスタイルの形をしながら、ListViewでの基本機能が多数取り揃えられているライブラリです。
例えば、ListViewのソート、選択項目に対する移動、削除などです。
このような機能を実現するにあたって、View⇔ViewModel⇔Modelのすべての領域にわたって素晴らしいクラスが提供されています。

完全に自画自賛です。


ところで、バグがありました。

ListViewViewModelでClear()を呼び出したとき、より正確にはRemoveなどで最後の1項目を削除したとき、InvalidOperationExceptionが発生することがあるバグがありました。

MoveUpSelectedItemCommand/MoveDownSelectedItemCommandの実装にて、このコマンドが有効になる条件として「選択されているアイテムの個数が1以上、かつリストの先頭/最後尾のアイテムが選択されていない」というロジックを組んでいました。
しかし、 最後の1つの項目を削除したときにSelectedItemsの反映がリストのコレクションの反映より遅くなることがあるようで、その場合、「選択されているアイテムが1個あるがリストのコレクションのアイテムは0個」という状況が起こってしまうようです。その時に、1つ目の条件をすり抜けて2つ目の条件の判定に入った際、リストの先頭または最後尾のアイテムを取得しようとしてInvalidOperationExceptionがスローされているようでした。

このバグは、「リストのコレクションの数が1個以上」という条件を追加することによって回避しました。


あと、自分で作っておいて少しはまったところですが、このライブラリ、UI以外のスレッドからアイテムの操作をしてもUIに正常に反映される仕組み(Dispatcher経由でのアクセス)に対応しているにもかかわらず、スレッドセーフに作られていません。
気が向いたらSorableSynchronizedObservableCollectionなどを作るかもしれませんが、それまでは皆さん自分でlockなどをして使ってくださいね…。

とりあえず、例の最後の1個を消したら例外を吐くバグを直したものをbeta2としてうpしておきました。
ListViewExtensions 1.0.0-beta2
細かな使い方はbeta1をリリースしたときの記事を確認してください。

いつになったらプレリリース外そうかな…。