今度のブログは落ちないこの広告は、90日以上更新していないブログに表示しています。https://github.com/ugaya40/LivetLivetの概要と導入方法Livet(リベット)はWPF4/4.5のためのMVVM(Model/View/ViewModel)パターン用インフラストラクチャです。Profile以上で動作し、zlib/libpngライセンスで提供しています。zlib/libpngライセンスでは、ライブラリとしての利用に留めるのであれば再配布時にも著作権表示などの義務はありません。ソースコードを改変しての再配布にはその旨の明示が義務付けられます。2010/2012用プロジェクトテンプレート・アイテムテンプレート・コードスニペットを提供しています。2010/2012の拡張機能マネージャから一発で簡単に導入できます。ライブラリだけならNugetからも導入が可能です。場合はmsiインストーラからインストールしてください。SupportLivetは極力VisualStudioとExpressionBlendの機能を活かす作りにしています。対応WPFでは、プロジェクトの初期設定のコストも馬鹿になりません。ビヘイビア・トリガー・アクションの開発にも高いコストがかかります。Livetではプロジェクトテンプレート・アイテムテンプレートはもちろんの事、コードスニペットにて各種Commad、変更通知プロパティを提供しています。Blend親和性(Blendable)LivetのView機能は極力Blendで作業しやすくなるように定義されています。SupportLivetのViewサポートの方針は簡単です。WPFに限らずMVVMに限らずXAML系プラットフォームの特徴を活かしたViewサポートライブラリに出来る事はもともと基本的に「Viewコントロールの機能の補完」と「バインドで解決できる場所を増やす」のみです。LivetはMVVMインフラストラクチャですから「バインドで解決できる箇所を増やす」に注力するのは至極当然と言えます。バインドできないプロパティをバインドするコントロールのバインドできないプロパティ(依存関係プロパティではないプロパティ)の存在がViewModelでのViewの状態管理を苦しくする事は少なくありません。Livetではすべてのコントロールの、全ての(System.Windowsで始まる型のプロパティは除く)依存関係プロパティではないプロパティの単方向のバインドを可能にするビヘイビアとアクションを提供しています。(バインドソースからxxxコントロールへ値を送信)また、TextBoxとPasswordBoxに限っては本来バインドできないプロパティを双方向バインド可能にするビヘイビアを別途用意してあります。(TextBoxBindingSupportBehavior/PasswordBoxBindingSupportBehavior)。メソッド直接バインディング一般的なMVVMのサンプルとされるコードでViewからViewModelに操作を要求したい時にICommandを介するのは何故か?。Viewの抽象化要件の上ではICommandはViewModelで意味的な操作の塊を提示するという意義があります。多くの場合Viewの抽象要件は不要です。Viewの抽象化要件がなく、Modelが十分にリッチでViewModelが適切な厚さを持っている場合、ICommandはただメソッドを直接バインドできないがために存在します。その状況(つまり多くの状況)でMVVMを適切に考慮すれば、それはむしろICommandを使わない事になるはずです。LivetではICommandをサポートするすべてのView機能が同時にメソッドの直接バインディングをサポートしています。代表的なそれはLivetCallMethodActionです。BlendSDKのCallMethodActionは引数はとれませんが、LivetCallMethodActionは一つの引数を取れ(ICommandと同条件)、なおかつBlendSDKのCallMethodActionより高いパフォーマンスを誇ります。LivetCallMethodAction後述するメッセージ機構も含めてLivetにおいてはすべてのICommandを要求するような機能が同時にメソッドの直接バインディングをサポートしていますし、開発者が独自にビヘイビア・トリガー・アクションを作成する際もメソッドの直接バインディングが簡単に実装できるようにMethodBinderという機構を用意してあります。MethodBinderはLivetのすべてのメソッドバインディング機能で使用されています。MethodBinderをシンプルに使用するだけで、内部ではリフレクションと式木をフル活用して最大限メソッドキャッシュ管理の効率化をしてくれます。Messageを受け取るアクションLivet.Behaviors.Messaging名前空間にはメッセージを受け取る事の出来るActionが用意されています。メッセージを受け取るActionは汎用性が高く、View上でEventTriggerなどから通常通りActionを起動する事も、ViewModel上のMessengerからMessageを送信して起動する事もできます。戻り値のあるメッセージに対応したActionでは、Actionの結果が格納されたメッセージを引数にViewModelのメソッドやコマンドを呼び出すこともできます。PrismのInteractionRequestと似た機構ですが、決定的に異なるのはメッセージをView上でも定義可能なところとコールバックをコマンド呼び出しだけではなくメソッドでも可能な所です。View上でメッセージが定義できる事で実装上の制約からくるViewとViewModel間の不要な通信を抑える事ができます。メッセージを受け取るアクションは、通常通りのアクションとして使う事も、ViewModel→View方向の通知手段として使う事も出来ます。Packを参照しているためLivet.Extensionsという別アセンブリに定義)などがあります。Livet.Extensionsのフォルダー選択メッセージとアクションは、Vista以前と以降でTaskDialogとFolderBrowserDialogを自動で切り替えて使用できるまた、開発者が簡単にメッセージ対応アクション・メッセージを定義できるように、アイテムテンプレートに相互作用アクションとメッセージのテンプレートをそれぞれ用意してあります。汎用EnumToBooleanConverterView抽象化要件がない場合、Converterを使わなければならない箇所は限られては来ますが、しかしそれでもViewModelの使いまわしをしたい等の場合にIValueConverterを必要とする場合があります。LivetではSystem.Windows名前空間配下の全てのEnum型をbooleanと相互変換するIValueConverterを用意してあります。SDKのDataTriggerは初期値に対応していません。その対処として初期値に対応するLivetDataTrigger、フォーカスを制御するSetFocusAction、Windowのクローズキャンセルや、クローズキャンセル可否判断をViewModelに委譲する事が出来るWindowCloseCancelBehavior、RoutedEventTrigger、DataContextがIDisposableであった場合DataContextをDisposeするDataContextDisposeActionなどを用意してあります。SupportLivetのViewModelサポート機能は、ViewとModelを極力PDSにそってデザインした場合に必然的に薄くなるViewModel、そしてその薄くなったViewModelが多くの開発シナリオで多用するであろう機能を前提にデザインしてあります。メッセージを受け取るアクションに、ViewModelからメッセージを伝えるために用意されています。CompositeDisposableはIEnumerable<IDisposable>型で、ViewModelがDisposeされる際に同時に破棄したいリソースを格納するために使用されます。LivetのViewModel機能を使用する場合は、ViewModelと一緒に破棄したいリソースは基本的にViewModelのCompositeDisposableに格納する事になります。ReactiveExtensionsと併用する場合には、RxのCompositeDisposableをLivetのViewModelのCompositeDisposableに放り込んでやるとよいでしょう。DispatcherCollectionとReadOnlyDispatcherCollectionDispatcherCollectionは、既存の変更通知コレクションをコンストラクタの引数にとり、その変更通知を指定されたDispatcher上で行うコレクションです。ReadOnlyDispatcherCollection、DispatcherCollectionをコンストラクタの引数にとる読み取り専用ラッパーとなります。ViewModelHelper.CreateReadOnlyDispatcherCollection<TModel,TViewModel>CreateReadOnlyDispatcherCollectionを使用すると、Modelの変更通知コレクションを指定し、そのModelのコレクションの変更と連動するReadOnlyDispatcherCollectionを生成できます。Func<TModel,TViewModel>を指定してTModel型とTViewModel型の相互変換を行います。CreateReadOnlyDispatcherCollectionを使用して生成されたTViewModelの要素がIDisposableであった場合、sourceコレクションからRemoveされた場合など要素削除時にはDisposeが呼ばれます。生成されたコレクションのDisposeを呼ぶことで、ソースコレクションとの連動は解除され、TViewModelがIDisposableであった場合は生成されたTViewModel型に対してDiposeが呼ばれます。PropertyChangedEventListener/CollectionChangedEventListenerModelのイベントを監視するのはViewModelの大きな役目です。C#ではイベントハンドラの監視と解除を以下のような構文で行えません。Livetでは特に煩雑になりがちなPropertyChangedイベントの監視と解除を容易にするため、PropertyChangedEventListenerクラスを用意してあります。様々な形でのPropertyChangedイベントハンドリングCollectionChangedEventListenerはそのコレクション変更通知版です。PropertyChangedEventListenerほど多機能ではありませんが似た様な事が可能です。汎用EventListenerとしてEventListenerを用意してあります。EventListenerやPropertyChangedEventListener/CollectionChangedEventListenerはIDisposable型であり、Disposeする事でハンドラの監視を解除します。ViewModelのCompositeDisposableに放り込んでおけば何も考えずともイベントハンドラの監視解除が行えます。SupportModelはMVVMの関心領域ではないため、Livetでも特に手厚いサポートはありません。最低限の機能として、変更通知イベント基底クラスとなるNotificationObjectと、スレッドセーフな変更通知コレクションであるObservableSynchronizedCollectionを用意してあります。ObservableSyncronizedCollectionはMonitorベースのスレッドセーフなコレクションではなく、ReaderWriterLockSlimによるスレッドセーフなコレクションであり、読み書きが等しく複数スレッドから煩雑に行われるシナリオにおいて、パフォーマンスと変更通知のタイミングの偏りのバランスが良い様に設計されています。前述したViewModelのDispatcherCollectionはただのラッパーであるため、Modelでは通常のObservableCollectionとObservableSyncronizedCollectionを用途に応じて使い分け、それをViewModelでは同様に扱う事ができます。StatefulModelはModel-View-Whateverにお...2015-01-17MVVMのModelにまつわる誤解こちらに移転してきて初めての記事です。12はてなブログをはじめよう!m_onoueさんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。