First off, I'm using Xamarin Studio 6.1.3 in case that makes any difference.
I'm creating a simple app and want a login form to appear as a sheet. I followed the Xamarin tutorial for creating sheets (https://developer.xamarin.com/guides/mac/user-interface/working-with-dialogs/#Creating_a_Custom_Sheet) but am running into an issue.
Per the tutorial, I have created a class:
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);
}
}
}
And I have added an override for PrepareForSegue in my ViewController class:
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;
}
}
See the comment in the above code block. I basically set a breakpoint on that line and when it triggers, I inspect the loginSheet object. If I expand the Base object to inspect it and then continue execution, everything works as expected. If I don't, I get a NullReferenceException whenever code tries to access any fields/properties/methods in the UserLoginController class.
I am completely baffled as to why this is happening. I set a breakpoint in the constructor of UserLoginController and verified it is being called with a handle and that the base constructor should be called as well.
I've read through the tutorial several times and don't see anything that I'm missing. Can't seem to find anybody else having the same problem.
My ultimate question is: What can I do to make the code work as expected?
For the sake of learning (which may shed light on the problem): What is going on behind the scenes when I inspect the base object of my UserLoginController class while debugging?
The solution turned out to be that I need to check the
View
property of myUserLoginController
.I added the following line:
and everything works as expected. I have yet to dig into the
View
property to see what it is doing behind the scenes that makes everything work.Here is the modified, working
PrepareForSegue
override method: