2017-01-02 39 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

相关问题