与MvvmCross绑定期间出现NullReference异常

时间:2013-09-23 08:37:12

标签: mvvmcross

我有一个使用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调试输出没有提示我有什么问题。有什么想法吗?

3 个答案:

答案 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)

这应该是一个更好的答案:

  • 第1步:您正在混淆:如果您创建自己的视图,请覆盖LoadView而不是ViewDidLoad。并确保没有关联的Xib。
  • 步骤2:在loadview中,由于MvvmCross缺点而调用ViewDidLoad(它将在ViewDidLoad之后绑定ViewModel,但仅在Xib之后调用ViewDidLoad)。

我认为MvvmCross拥有对原始View的引用,而不是您在ViewDidLoad中定义的(已创建的)View。

使用没有Xib的MvvmCross工作正常(我再也不会创建任何Xib),我真的推荐XibFree(让我的fork具有扩展功能)。