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 で変更通知をします。
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() の中身は空でも大丈夫です。
public App() { Mvx.RegisterType<ICalculation, Calculation>(); // Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<TipViewModel>()); }
RegisterSingleton を使うとシングルトンで作られてしまい、都合が悪いことが多いので、UI プロジェクトのほうで作ります。
TipCalc.UI.Touch の中身
Setup.cs の中身はほとんど空っぽです。
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 自体を変えてしまってもいいのですが。
[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;
することを忘れずに…いつもあれ?ってなるので。
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