2013-09-23 52 views
1

我有一個使用MvvmCross的MonoTouch項目。我處於可以編譯我的核心項目代碼的階段(付出了相當大的努力),現在我正在爲iOS創建視圖。運行Xamarin工具的最新穩定版本,以及MvvmCross。另外,我針對安裝了XCode 5的iOS7 SDK運行。在與MvvmCross綁定期間的NullReference異常

首先,我創建了一個非常基本的視圖,其中的文本字段綁定到我的主視圖模型。在視圖中的相關代碼如下:

[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]中:在Cirrious.MvvmCross.Binding.BindingContext.MvxFluentBindingDescription 1[MonoTouch.UIKit.UITextField].To[MainViewModel] (System.Linq.Expressions.Expression 1名在SourceProperty)[0x00000]在0 :0 在ProjectX.Views.MainView.ViewDidLoad( )/ Users/jerriepelser/Dev中的[0x000a4] MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend(intptr,intptr) at MonoTouch.UIKit.UIWindow(1)打印/ 1degree軟件/ ProjectX/Source/ProjectX.MonoTouch/Views/MainView.cs:26 at(wrapper managed-to-native) .MakeKeyAndVisible()[0x00010]位於/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 /在ProjectX.Application.Main(System.String [] args)中的UIKit/UIApplication.cs:38 /Users/jerriepelser/Development/1degree Software/ProjectX/Source/ProjectX.MonoTouch/Main.cs中的[0x00008]:16

如果我在綁定之前設置了一個斷點,我可以確認ViewModel在基礎MvxViewController類上正確設置,所以它不是沒有設置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]在:0 在Cirrious.MvvmCross.Binding.BindingContext.MvxFluentBindingDescription 2[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(包裝託管到本機)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 位於/ Users/jerriepelser/Development/1degree Software/OneLove/Source/OneLove.MonoTouch/AppDelegate中的OneLove.AppDelegate.FinishedLaunching(MonoTouch.UIKit.UIApplication應用程序,MonoTouch.Foundation.NSDictionary選項)[0x0003c]。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)在/Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38 處的OneLove.Application.Main(System.String [] args)[0x00008]中的[0x0004c]/Users/jerriepelser/Development/1degree Software/OneLove/Source/OneLove.MonoTouch/Main.cs:16

看着MvvmCross調試輸出,我不知道什麼是錯的。有任何想法嗎?

+0

不知道。這個錯誤表明,也許你錯過了其中一個解析器 - 但我想不出任何你會錯過正常的'第一個應用'集合中的方式。也許你有某種混合搭配的程序集,或者有一個Xamarin設置問題?像https://github.com/slodge/Enabling這樣的簡單測試項目是否適合您?如果是的話,那麼看看你能否發現這種差異。如果不是,那麼請使用完整跟蹤來更新問題(或鏈接到完整跟蹤的要點) – Stuart

+0

我無法在Xamarin Studio中使用NuGet來運行MvvmCross,因此我下載了最新的二進制文件並引用了它。我不知道它是否是組合混音,因爲我引用的是同一個「Touch」文件夾中的所有文件,除了我從「Portable」文件夾引用的那些文件以外。按照你的建議,會再次經歷它,因爲我用手做了所有事情,並且可能會在我身邊搞砸。 –

+0

開始一個新項目,讓Nuget包按照這個問題的描述工作:http://stackoverflow.com/questions/17653208/getting-pcl-mvvmcross-nuget-and-xamarin-studio-to-play-nice-on -蘋果電腦。它的工作狀況很好,所以我會明天將我的項目退回到骨頭,並嘗試找出問題所在。 –

回答

2

好的,我解決了它。我認爲這個答案可能並不適用於所有情況,但我的情況是它將問題排除在外。

我在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()...

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(); 
     } 




    } 
+0

哎呀抱歉,這是Android代碼。我會把這個留給其他遇到這些問題的人。 –

0

這應該是一個更好的答案:

  • 第1步:你混合起來的東西:如果您創建自己的視圖,請覆蓋LoadView而不是ViewDidLoad。並確保沒有關聯的Xib。
  • 步驟2:在loadview中,由於MvvmCross的缺點(它將在ViewDidLoad之後綁定ViewModel,但ViewDidLoad僅在Xib之後調用)調用ViewDidLoad。

我認爲MvvmCross擁有對原始視圖的引用,而不是您在ViewDidLoad中定義的(後期創建的)視圖。使用沒有Xibs的MvvmCross工作正常(我從來沒有創建任何Xib),並且我真的推薦XibFree(帶我的fork來擴展功能)。

+0

''ViewDidLoad'只在Xib'對我聽起來不正確時才被調用。這是第一次引用視圖,無論它是否是Xib加載 - 現在有數百個Mvx示例 - 例如所有這些在https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs中。 – Stuart

+0

'我認爲MvvmCross擁有對原始視圖的引用 - 不是我所知道的 - *應該是* UIView引用綁定到開始創建/應用綁定。如果您發現有問題,請記錄問題。 – Stuart

+0

@Stuart,如果我可以再次構建iOS,我會測試它們:(自從兩年前我切換到Xibless構建之後,我一直對這個問題感到厭倦:ViewDidLoad並不總是被調用,但是我認爲在在這種情況下,我添加了ViewDiDLoads來準備LoadView中的數據綁定,而不必將所有項目公開爲全部屬性/字段,但我會稍後檢查它們,所有操作都以「應用程序是國王」的名義完成:) –