Xamarin.iOS+MvvmCrossでstoryboardを使う方法 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5814
以前、書いたのですが、バージョンが上がって微妙に動きが異なっているので、メモ書きしておきます。
サンプルコードは http://1drv.ms/1CeHWYp からダウンロードができます。
MvvmCross のサンプルコードを storyboard 対応にする
Tip Calc The Core Project
https://github.com/MvvmCross/MvvmCross/wiki/Tip-Calc—The-Core-Project
Tip Calc A Xamarin.iOS UI project ・ MvvmCross/MvvmCross Wiki
https://github.com/MvvmCross/MvvmCross/wiki/Tip-Calc-A-Xamarin.iOS-UI-project
TipCalc.Core の中身
ViewModel は MvxViewModel クラスを継承して作ります。ここのバインドは、INotiryPropertyChanged を実装していればよいので、何で作っても良いはずです。
プロパティの変更時に、RaisePropertyChanged で変更通知をします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class TipViewModel : MvxViewModel { private readonly ICalculation _calculation; public TipViewModel(ICalculation calculation) { _calculation = calculation; } public override void Start() { _subTotal = 100; _generosity = 10; Recalcuate(); base .Start(); } private double _subTotal; public double SubTotal { get { return _subTotal; } set { _subTotal = value; RaisePropertyChanged(() => SubTotal); Recalcuate(); } } |
App.cs の中身は、空っぽでも動きます…と思ったけど、Calculation のインスタンスだけ作らないとダメです。この部分は、Calc 部分を ICalc で作っているので、こうなっているので、特に作らなければ App() の中身は空でも大丈夫です。
1 2 3 4 5 | public App() { Mvx.RegisterType<ICalculation, Calculation>(); // Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<TipViewModel>()); } |
RegisterSingleton を使うとシングルトンで作られてしまい、都合が悪いことが多いので、UI プロジェクトのほうで作ります。
TipCalc.UI.Touch の中身
Setup.cs の中身はほとんど空っぽです。
1 2 3 4 5 6 7 8 9 10 11 12 | public class Setup : MvxTouchSetup { public Setup(MvxApplicationDelegate appDelegate, IMvxTouchViewPresenter presenter) : base (appDelegate, presenter) { } protected override Cirrious.MvvmCross.ViewModels.IMvxApplication CreateApp() { return new App(); } } |
AppDelegate.cs の中身は、Window プロパティを残して、FinishedLaunching だけオーバーライドします。
内部で window を作っているサンプルコードもあるのですが、別のところから Window プロパティを参照することができるので、元の状態で残したほうがベターです。
以前と違って、Setup の引数が変わっているので、MvxTouchViewPresenter オブジェクトを作って引き渡します。
まあ、Setup 自体を変えてしまってもいいのですが。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [Register( "AppDelegate" )] public partial class AppDelegate : MvxApplicationDelegate { // class-level declarations public override UIWindow Window { get ; set ; } public override bool FinishedLaunching(UIApplication app, NSDictionary options) { var presenter = new MvxTouchViewPresenter( this , Window); var setup = new Setup( this , presenter); setup.Initialize(); return true ; } } |
TipCalc.UI.TouchViewController.cs の ViewModel は、MvxViewController を継承するように変更して、ViewDidLoad メソッドの中身だけ変更します。
base.ViewDidLoad で元のメソッドを呼び出す前に、MvxViewModelRequest オブジェクトを作らないといけません。この引数が変更になっていて、ViewModel のクラス名(ここでは TipViewModel )を渡します。
CreateBindingSet は拡張メソッドなので、
using Cirrious.MvvmCross.Binding.BindingContext;
することを忘れずに…いつもあれ?ってなるので。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public partial class TipCalcUITouchViewController : MvxViewController { public TipCalcUITouchViewController(IntPtr handle) : base (handle) { } public new TipViewModel ViewModel { get { return (TipViewModel) base .ViewModel; } set { base .ViewModel = value; } } public override void ViewDidLoad() { this .Request = new MvxViewModelRequest( typeof (TipViewModel), null , null , new MvxRequestedBy()); base .ViewDidLoad(); // Perform any additional setup after loading the view, typically from a nib. var set = this .CreateBindingSet<TipCalcUITouchViewController, TipViewModel>(); set .Bind(labelTip).To(vm => vm.Tip); set .Bind(textSubTotal).To(vm => vm.SubTotal); set .Bind(sliderGene).To(vm => vm.Generosity); set .Apply(); } } |
Bind でコントロールを指定して、To で ViewModel のプロパティと結びつけます。いわゆる Binding の Path は .For( c => c.Text) で明示的に指定もできますが省略可能です(デフォルトプロパティを内部で持っていると思われる)。
実行結果
こんな風にスライダーを動かすと、ラベルの数値が変化します。
サンプルコード
サンプルはこちら
http://1drv.ms/1CeHWYp