前回の投稿 で Prism の Xamarin 用 MVVM 基盤の拡張に光が見えたので、さっそく作ってみます
まずはプロジェクトの追加から
ViewModel のバインディングをするので Xamarin.Forms の PCL クラスライブラリプロジェクトを選んで追加します
データバインディングはおそらく Xamarin.Forms 主体になると思うので ViewModelLocator も Xamarin.Forms のクラスライブラリで記述すれば大丈夫なはずだからです
このプロジェクトに Prism.Mvvm と Prism.SharedInterfaces のプロジェクト参照も追加します
あとは Xamarin.Forms 用の ViewModelLocator を記述するだけ!
まぁでも簡単です
/// <summary> /// ViewModel のロケータ /// </summary> public static class ViewModelLocator { /// <summary> /// ViewModel を自動的にバインドするか否かを表す BindableProperty /// </summary> public static readonly BindableProperty AutoWireViewModelProperty = BindableProperty.Create( "AutoWireViewModel", typeof(bool), typeof(ViewModelLocator), false, BindingMode.TwoWay, null, AutoWireViewModelChanged); /// <summary> /// AutoWireViewModelProperty の変更イベントハンドラ /// </summary> /// <param name="bindable">BindableObject</param> /// <param name="oldValue">変更前の値</param> /// <param name="newValue">変更後の値</param> private static void AutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue) { var view = bindable as IView; if (view == null) { throw new Exception("Your views must implement IView"); } ViewModelLocationProvider.AutoWireViewModelChanged(view); } /// <summary> /// AutoWireViewModel を取得します /// </summary> /// <param name="bindable">バインドされている BindingContext</param> /// <returns>自動的にバインドされた ViewModel が利用可能な場合 <c>true</c> それ以外は <c>false</c></returns> public static bool GetAutoWireViewModel(BindableObject bindable) { if (bindable != null) { return (bool)bindable.GetValue(AutoWireViewModelProperty); } return false; } /// <summary> /// AutoWireViewModel を 設定します /// </summary> /// <param name="bindable">バインドされている BindingContext</param> /// <param name="value"><c>true</c> を設定した場合自動的に ViewModel がバインドされます</param> public static void SetAutoWireViewModel(BindableObject bindable, bool value) { if (bindable != null) { bindable.SetValue(AutoWireViewModelProperty, value); } } }
本家の ViewModelLocator の DependencyProperty を BidableProperty に書き直すだけです
追加後のソリューション構成はこんな感じ
ただ実際に利用する場合にはもうひと手間かかりそうです
/// <summary> /// Prism 用 ContentView の基底クラス /// </summary> public class ContentViewBase : ContentView, IView { #region IView /// <summary> /// Bindable DataContext /// </summary> public object DataContext { get { return this.BindingContext; } set { this.BindingContext = value; } } #endregion //IView }
ViewModelLocator の中で利用している IView のインタフェースは DataContext を参照可能にしますが、Xamarin.Forms だと BindingContext なのでその差異を吸収する必要があります
なので、View を利用する場合そのままではなく必ず IView インタフェースを実装しなければなりません
こういうところで微妙に名前の違うことの弊害を感じる・・・まぁとりあえずはこれで本家 Prism みたいに ViewModelLocator が利用できるようになるでしょうか?!