我有一个使用MvvmCross的MonoTouch项目。我正处于可以获得核心项目代码编译的阶段(需要付出相当大的努力),现在我正在为iOS创建视图。运行Xamarin工具的最新稳定版本以及MvvmCross。另外,我正在运行安装了XCode 5的iOS7 SDK。
首先,我创建了一个非常基本的视图,其中一个文本字段绑定到我的主视图模型。视图中的相关代码如下:
[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();
}
}
然而,绑定会抛出NullReference异常,并带有以下堆栈跟踪:
System.NullReferenceException:未将对象引用设置为对象的实例
在Cirrious.MvvmCross.Binding.BindingContext.MvxBaseFluentBindingDescription 1[MonoTouch.UIKit.UITextField].SourcePropertyPath[MainViewModel] (System.Linq.Expressions.Expression
1 sourceProperty)[0x00000] in:0
在Cirrious.MvvmCross.Binding.BindingContext.MvxFluentBindingDescription 1[MonoTouch.UIKit.UITextField].To[MainViewModel] (System.Linq.Expressions.Expression
1 sourceProperty)[0x00000] in:0
在/ Users / jerriepelser / Development / 1degree Software / ProjectX / Source / ProjectX.MonoTouch / Views / MainView.cs中的ProjectX.Views.MainView.ViewDidLoad()[0x000a4]:26
at at(wrapper managed-to-native)MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend(intptr,intptr)
在/Developer/MonoTouch/Source/monotouch/src/UIKit/UIWindow.g.cs:129中的MonoTouch.UIKit.UIWindow.MakeKeyAndVisible()[0x00010]
在ProjectX.AppDelegate.FinishedLaunching(MonoTouch.UIKit.UIApplication应用程序,MonoTouch.Foundation.NSDictionary选项)[0x0003c]在/ 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)
在/Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38中的MonoTouch.UIKit.UIApplication.Main(System.String [] args,System.String principalClassName,System.String delegateClassName)[0x0004c]
在ProjectX.Application.Main(System.String [] args)[0x00008] / Users / jerriepelser / Development / 1degree Software / ProjectX / Source / ProjectX.MonoTouch / Main.cs:16
如果我在绑定之前设置断点,我可以确认在基本MvxViewController类上正确设置了ViewModel,因此没有设置ViewModel的问题。
我还尝试了以下数据绑定方式:
var set = this.CreateBindingSet<MainView, MainViewModel> ();
set.Bind (uiTextField).To (vm => vm.IsDebug);
set.Apply ();
仍然获得NullReference异常,但使用以下堆栈跟踪:
System.NullReferenceException:未将对象引用设置为对象的实例
在Cirrious.MvvmCross.Binding.BindingContext.MvxBaseFluentBindingDescription 1[MonoTouch.UIKit.UITextField].SourcePropertyPath[MainViewModel] (System.Linq.Expressions.Expression
1 sourceProperty)[0x00000] in:0
在Cirrious.MvvmCross.Binding.BindingContext.MvxFluentBindingDescription 2[MonoTouch.UIKit.UITextField,OneLove.Core.ViewModels.MainViewModel].To (System.Linq.Expressions.Expression
1 sourceProperty)[0x00000] in:0
在/ Users / jerriepelser / Development / 1degree Software / OneLove / Source / OneLove.MonoTouch / Views / MainView.cs中的OneLove.Views.MainView.ViewDidLoad()[0x000a6]:29
at at(wrapper managed-to-native)MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend(intptr,intptr)
在/Developer/MonoTouch/Source/monotouch/src/UIKit/UIWindow.g.cs:129中的MonoTouch.UIKit.UIWindow.MakeKeyAndVisible()[0x00010]
at OneLove.AppDelegate.FinishedLaunching(MonoTouch.UIKit.UIApplication app,MonoTouch.Foundation.NSDictionary选项)[0x0003c]在/ 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)
在/Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38中的MonoTouch.UIKit.UIApplication.Main(System.String [] args,System.String principalClassName,System.String delegateClassName)[0x0004c]
在/ Users / jerriepelser / Development / 1degree Software / OneLove / Source / OneLove.MonoTouch / Main.cs中的OneLove.Application.Main(System.String [] args)[0x00008]:16
查看MvvmCross调试输出没有提示我有什么问题。有什么想法吗?
答案 0 :(得分:3)
我在Setup类的InitializeLastChance方法中进行了一些特定于平台的IOC注册,但是没有调用base.InitializeLastChance()。这不会导致WinRT或Windows Phone 8出现问题,但在MonoTouch上会导致我遇到的错误。所以我对基类方法做了一个简单的调用,所有问题都解决了:)
protected override void InitializeLastChance()
{
base.InitializeLastChance ();
// Do some platform specific registration here...
}
如果其他人遇到类似的事情,这可能是导致错误的原因。
编辑: 只是一个快速的事后想想...看看基础MvxTouchSetup类的源代码,这实际上现在非常有意义:
protected override void InitializeLastChance()
{
InitialiseBindingBuilder();
base.InitializeLastChance();
}
请参阅对InitialiseBindingBuilder()的调用...
答案 1 :(得分:0)
我使用代码生成的视图遇到了同样的问题。
已设置Viewmodel,但未完全设置bindingcontext。以下是我的项目中的一些示例代码,可帮助您了解并遇到其他问题:
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 ();
}
}
答案 2 :(得分:0)
这应该是一个更好的答案:
我认为MvvmCross拥有对原始View的引用,而不是您在ViewDidLoad中定义的(已创建的)View。
使用没有Xib的MvvmCross工作正常(我再也不会创建任何Xib),我真的推荐XibFree(让我的fork具有扩展功能)。