2017-01-02 38 views
1

首先,我使用Xamarin Studio 6.1.3以防有所作爲。獲取NullReferenceException,除非我在調試時展開基類對象

我正在創建一個簡單的應用程序,並希望登錄表單顯示爲工作表。我遵循Xamarin教程創建工作表(https://developer.xamarin.com/guides/mac/user-interface/working-with-dialogs/#Creating_a_Custom_Sheet),但遇到了問題。

每本教程中,我創建了一個類:

using System; 
using Foundation; 
using AppKit; 

namespace SampleProject 
{ 
    public partial class UserLoginController : NSViewController 
    { 
    private NSViewController _presentor; 

    public string Username 
    { 
     get { return TxtUsername.StringValue; } 
     set { TxtUsername.StringValue = value; } 
    } 

    public string Password 
    { 
     get { return TxtPassword.StringValue; } 
     set { TxtPassword.StringValue = value; } 
    } 

    public NSViewController Presentor 
    { 
     get { return _presentor; } 
     set { _presentor = value; } 
    } 

    public UserLoginController(IntPtr handle) : base(handle) 
    { 

    } 

    private void CloseDialog() 
    { 
     Presentor.DismissViewController(this); 
    } 

    partial void BtnCancelClick(NSObject sender) 
    { 
     RaiseDialogCanceled(); 
     CloseDialog(); 
    } 

    partial void BtnLoginClick(NSObject sender) 
    { 
     RaiseDialogAccepted(); 
     CloseDialog(); 
    } 

    public EventHandler DialogAccepted; 

    internal void RaiseDialogAccepted() 
    { 
     if (this.DialogAccepted != null) 
      this.DialogAccepted(this, EventArgs.Empty); 
    } 

    public EventHandler DialogCanceled; 

    internal void RaiseDialogCanceled() 
    { 
     if (this.DialogCanceled != null) 
      this.DialogCanceled(this, EventArgs.Empty); 
    } 


    } 
} 

而且我在我的ViewController類增加了PrepareForSegue一個覆蓋:

public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender) 
    { 
     base.PrepareForSegue(segue, sender); 

     switch (segue.Identifier) 
     { 
      case "UserLoginSegue": 
       UserLoginController loginSheet = segue.DestinationController as UserLoginController; 
       loginSheet.Username = ""; //This line throws NullReferenceException unless I set a breakpoint and expand loginSheet.Base before allowing this line to execute. 
       loginSheet.Password = ""; 
       loginSheet.Presentor = this; 
       loginSheet.DialogAccepted += (object s, EventArgs e) => { Console.WriteLine("OK Clicked"); }; 
       loginSheet.DialogCanceled += (object s, EventArgs e) => { Console.WriteLine("Cancel Clicked"); }; 
       break; 
     } 
    } 

看到上面的代碼塊的註釋。我基本上在該行上設置了一個斷點,當它觸發時,我檢查了loginSheet對象。如果我展開Base對象來檢查它,然後繼續執行,則所有事情都按預期工作。如果我不這樣做,只要代碼嘗試訪問UserLoginController類中的任何字段/屬性/方法,就會得到一個NullReferenceException。

我完全不知道爲什麼會發生這種情況。我在UserLoginController的構造函數中設置了一個斷點,並驗證了它是用句柄調用的,並且基類構造函數也應該被調用。

我已經通讀了幾遍教程,沒有看到任何我錯過的東西。似乎無法找到其他人有相同的問題。

我的最終問題是:我能做些什麼來使代碼按預期工作?

爲了學習(這可能揭示問題):在調試時檢查UserLoginController類的基礎對象時發生了什麼?

回答

1

解決方案竟然是我需要檢查我的UserLoginControllerView屬性。

添加以下行:

var theView = loginSheet.View; 

,一切都按預期工作。我還沒有深入瞭解View屬性,看看它在幕後做了什麼。

下面是修改,工作PrepareForSegue重寫方法:

public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender) 
{ 
    base.PrepareForSegue(segue, sender); 

    switch (segue.Identifier) 
    { 
     case "UserLoginSegue": 
      UserLoginController loginSheet = segue.DestinationController as UserLoginController; 
      var theView = loginSheet.View; 
      loginSheet.Username = ""; 
      loginSheet.Password = ""; 
      loginSheet.Presentor = this; 
      loginSheet.DialogAccepted += (object s, EventArgs e) => { Console.WriteLine("OK Clicked"); }; 
      loginSheet.DialogCanceled += (object s, EventArgs e) => { Console.WriteLine("Cancel Clicked"); }; 
      break; 
    } 
} 
+1

「如果此屬性的值在訪問它時尚未設置,則視圖控制器會調用loadView方法。該方法依次設置視圖控制器的nibName和nibBundle屬性標識的nib文件的視圖。「 - https://developer.apple.com/reference/appkit/nsviewcontroller/1434401-view?language=objc –

+1

With這個新發現的信息我將調用LoadView(),而不是檢查View屬性,但根據LoadView的Apple文檔(https://developer.apple.com/reference/appkit/nsviewcontroller/1434405-loadview?language=objc) - 「不要調用這個方法。如果您需要調用此方法,請訪問視圖屬性。「該鏈接提供了更多有關直接調用LoadView方法的原因的更多信息。 – John

1

在調試器中展開對象時,所有未用某些屬性標記的屬性都通過反射讀取,以便我們可以在IDE中顯示它們。

也許其中一個屬性有副作用?你應該能夠使用反射再現效果,然後平分屬性列表以查看誰影響你的行爲。

+0

雖然在與同事交談今天它通過反射閱讀所有的念頭閃過我的腦海。我會試一試,讓你知道我找到了什麼。感謝提示。 – John

+0

使用反射讓我找到罪魁禍首。我張貼了一個答案的細節。再次感謝你提供的建議。 – John

相關問題