Reputation: 548
I have an MonoTouch project using MvvmCross. I am at the point where I could get my core project code compiling (with quite a bit of effort), and now I am creating the views for iOS. Running the latest stable releases of Xamarin tools, as well as MvvmCross. Also, I am running against iOS7 SDK with XCode 5 installed.
To start off I created a very basic view with a text field binding to my main view model. The relevant code in the view is as follows:
[Register("MainView")]
public partial class MainView : MvxViewController
{
public override void ViewDidLoad()
{
View = new UIView { BackgroundColor = UIColor.White };
base.ViewDidLoad();
var uiTextField = new UITextField(new RectangleF(0, 100, 320, 100));
Add(uiTextField);
this.CreateBinding(uiTextField).To<MainViewModel>(vm => vm.IsDebug).Apply();
}
}
The binding however throws a NullReference exception with the following stack trace:
System.NullReferenceException: Object reference not set to an instance of an object
at Cirrious.MvvmCross.Binding.BindingContext.MvxBaseFluentBindingDescription1[MonoTouch.UIKit.UITextField].SourcePropertyPath[MainViewModel] (System.Linq.Expressions.Expression
1 sourceProperty) [0x00000] in :0
at Cirrious.MvvmCross.Binding.BindingContext.MvxFluentBindingDescription1[MonoTouch.UIKit.UITextField].To[MainViewModel] (System.Linq.Expressions.Expression
1 sourceProperty) [0x00000] in :0
at ProjectX.Views.MainView.ViewDidLoad () [0x000a4] in /Users/jerriepelser/Development/1degree Software/ProjectX/Source/ProjectX.MonoTouch/Views/MainView.cs:26
at at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend (intptr,intptr)
at MonoTouch.UIKit.UIWindow.MakeKeyAndVisible () [0x00010] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIWindow.g.cs:129
at ProjectX.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication app, MonoTouch.Foundation.NSDictionary options) [0x0003c] in /Users/jerriepelser/Development/1degree Software/ProjectX/Source/ProjectX.MonoTouch/AppDelegate.cs:27
at at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at ProjectX.Application.Main (System.String[] args) [0x00008] in /Users/jerriepelser/Development/1degree Software/ProjectX/Source/ProjectX.MonoTouch/Main.cs:16
If I set a breakpoint before the binding I can confirm that the ViewModel is set correctly on the base MvxViewController class, so it is not a problem with the ViewModel not being set.
I also tried the following way of doing the data binding:
var set = this.CreateBindingSet<MainView, MainViewModel> ();
set.Bind (uiTextField).To (vm => vm.IsDebug);
set.Apply ();
Still get a NullReference exception, but with the following stack trace:
System.NullReferenceException: Object reference not set to an instance of an object
at Cirrious.MvvmCross.Binding.BindingContext.MvxBaseFluentBindingDescription1[MonoTouch.UIKit.UITextField].SourcePropertyPath[MainViewModel] (System.Linq.Expressions.Expression
1 sourceProperty) [0x00000] in :0
at Cirrious.MvvmCross.Binding.BindingContext.MvxFluentBindingDescription2[MonoTouch.UIKit.UITextField,OneLove.Core.ViewModels.MainViewModel].To (System.Linq.Expressions.Expression
1 sourceProperty) [0x00000] in :0
at OneLove.Views.MainView.ViewDidLoad () [0x000a6] in /Users/jerriepelser/Development/1degree Software/OneLove/Source/OneLove.MonoTouch/Views/MainView.cs:29
at at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend (intptr,intptr)
at MonoTouch.UIKit.UIWindow.MakeKeyAndVisible () [0x00010] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIWindow.g.cs:129
at OneLove.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication app, MonoTouch.Foundation.NSDictionary options) [0x0003c] in /Users/jerriepelser/Development/1degree Software/OneLove/Source/OneLove.MonoTouch/AppDelegate.cs:27
at at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at OneLove.Application.Main (System.String[] args) [0x00008] in /Users/jerriepelser/Development/1degree Software/OneLove/Source/OneLove.MonoTouch/Main.cs:16
Looking at the MvvmCross debug output gives me no hint as to what is wrong. Any ideas?
Upvotes: 1
Views: 3297
Reputation: 548
OK, I solved it. I think that this answer may not apply to every situation, but I my case it sorted the problem out.
I was doing some platform specific IOC registration in the InitializeLastChance method on the Setup class, but did not make a call to base.InitializeLastChance(). This does not cause a problem on either WinRT or Windows Phone 8, but on MonoTouch it results in the error I experienced. So I did a simple call to the base class method, and all is resolved :)
protected override void InitializeLastChance()
{
base.InitializeLastChance ();
// Do some platform specific registration here...
}
If someone else out there experiences something similar, this may be a possible cause of the error.
Edit: Just a quick afterthought... Looking at the source code for the base MvxTouchSetup class, this actually makes perfect sense now:
protected override void InitializeLastChance()
{
InitialiseBindingBuilder();
base.InitializeLastChance();
}
See the call to InitialiseBindingBuilder()...
Upvotes: 3
Reputation: 2252
This should be a better answer:
I think MvvmCross holds a reference to the original View, instead of the (late created) View you define in ViewDidLoad.
Using MvvmCross without Xibs work fine (I never create any Xib anymore), and I really recommend XibFree (take my fork to have extended functionality).
Upvotes: 0
Reputation: 2252
I ran into the same problem using Views generated from code.
The Viewmodel is set, but the bindingcontext is not completely set. Here is some example code from my project to get you up and running for other issues you will encounter:
public abstract class IndexBaseFragment<T> : MvxFragment where T : class, IMvxViewModel {
public static int WRAP = ViewGroup.LayoutParams.WrapContent;
public static int FILL = ViewGroup.LayoutParams.FillParent;
public LinearLayout NewVerticalLinearLayout(Orientation orientation, Boolean fillparent) {
var ll = new LinearLayout (Activity) { Orientation = orientation };
ll.LayoutParameters = new ViewGroup.LayoutParams (FILL, fillparent ? FILL : WRAP);
return ll;
}
public new T ViewModel { get { return base.ViewModel as T; } set { base.ViewModel = value; } }
// These are the available controls
protected ListView list {get; set;}
protected MvxListView ListAsMvxListView {get { return (MvxListView) list; }}
protected TextView emptytext { get; set; }
protected TextView title { get; set; }
protected Button twobuttonklein { get; set; }
protected Button twobuttongroot { get; set; }
protected EditText zoekvak {get; set;}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var layout = NewVerticalLinearLayout (Orientation.Vertical, true);
if (ViewModel == null)
ViewModel = Mvx.IocConstruct<T> ();
BindingContext = new MvxAndroidBindingContext (Activity, new MvxSimpleLayoutInflater(inflater), ViewModel);
using (new MvxBindingContextStackRegistration<IMvxAndroidBindingContext>(((IMvxAndroidBindingContext) this.BindingContext)))
{
//var layout = NewVerticalLinearLayout (Orientation.Vertical, true);
layout.SetBackgroundColor (Color.ParseColor("#FFFFFF"));
var titlelayer = NewVerticalLinearLayout (Orientation.Horizontal, false);
titlelayer.LayoutParameters.Height = 40;
title = new TextView (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, FILL) };
title.SetTextColor (Color.ParseColor ("#212121"));
title.SetPadding(0, 10, 0, 0);
title.TextSize = 18;
var titlebutton = new Button (Activity) { LayoutParameters = new ViewGroup.LayoutParams (WRAP, FILL) };
titlelayer.AddView (title);
titlelayer.AddView (titlebutton);
layout.AddView (titlelayer);
var twobuttonlayer = NewVerticalLinearLayout (Orientation.Horizontal, false);
twobuttonlayer.LayoutParameters.Height = 40;
twobuttonklein = new Button (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP) };
twobuttonklein.Text = "Klein";
twobuttonklein.SetBackgroundResource (Resource.Drawable.kleingrootbutton);
twobuttongroot = new Button(Activity){ LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP) };
twobuttongroot.Text = "Middel/groot";
twobuttongroot.SetBackgroundResource (Resource.Drawable.kleingrootbutton);
twobuttonlayer.AddView (twobuttonklein);
twobuttonlayer.AddView (twobuttongroot);
layout.AddView (twobuttonlayer);
zoekvak = new EditText (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP) };
zoekvak.Hint = "Zoek in inhoudsopgave";
layout.AddView (zoekvak);
emptytext = new TextView (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, FILL),
Text = "Er zijn geen resultaten." };
layout.AddView (emptytext);
CreateList();
layout.AddView (list);
}
//var view = this.BindingInflate(Resource.Layout.IndexTocView, null);
Console.WriteLine ("LAYOUT RETURNED");
return layout;
}
protected abstract void BindView();
protected MvxAdapter listadapter { get; set; }
protected virtual void CreateList () {
// let op, deze code is nog voor de speciale situatie, en dat moet juist andersom.
listadapter = new MvxAdapter(this.Activity, (IMvxAndroidBindingContext)BindingContext);
list = new MvxListView(Activity, null, listadapter) { LayoutParameters = new ViewGroup.LayoutParams(FILL, FILL) };
list.SetMinimumHeight(50);
}
public override void OnResume ()
{
base.OnResume ();
BindView ();
}
}
Upvotes: 0