Problems
Recently when trying to open iOS UI Designer to edit storyboard/xib file, I have encounter some problems. This issue is also reported in Xamarin BugZilla: https://bugzilla.xamarin.com/show_bug.cgi?id=59623
Problem 1: ViewControler is rendered but with error exclamation mark
There are many different errors but this is the most common error: System.NullReferenceException
Problem 2: UI Designer took very long time to load and not able to render custom view
After UI Designer is startup, it will show a warning bar at the top. In this mode, all custom view is not rendered.
Checking in the log files and you might get the following errors:
System.NullReferenceException: Object reference not set to an instance of an object at MonoTouch.Design.Client.IPhoneDesignerSession+<MaybeConvertToLatestXcode>c__async5.MoveNext () [0x0004c] in /Users/builder/data/lanes/4470/6c2f6737/source/md-addins/Xamarin.Designer.iOS/MonoTouch.Design.Client/IPhoneDesignerSession.cs:774
Reasons & Solutions
After checking into the log file, found out that the UI Designer actually call into UIViewController
‘s (those that defined in the storyboard/xib) ViewDidLoad
method. In the ViewDidLoad method, I have some code that is dependency injection which is not available during design time. This is the reason why there is NullReferenceException
when render.
Attempt 1: Do not run code in ViewDidLoad during design time
I have defined a boolean IsDesignTime
in AppDelegate.cs
. By default it is set to true and it will set to false when called into FinishedLaunching
method in AppDelegate. Then in ViewDidLoad
method, I will check only when IsDesignTime
is false
, I will run the code.
// AppDelegate.cs
public class AppDelegate : UIApplicationDelegate
{
public static bool IsDesignTime = false;
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
IsDesignTime = false;
return true;
}
...
}
// ViewController.cs
public partial class ViewController : UIViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
if (!AppDelegate.IsDesignTime)
{
// Do something
}
}
...
}
This method can solve the problem and the view is able to render correctly in UI Designer again. However, it is kind of troublesome to add this checking every time. In addition, this method seems not working for views that inherit from UITableViewController
.
Attempt 2: Set the ViewController DesignTimeVisible flag to false
Checking in the UI Designer, you will find that under the Toolbox
, the ViewController is also showing as a custom component.
This is the reason why the ViewController
‘s ViewDidLoad
method is getting call during design time.
To remove the screen from being use as a custom components, we will need manually add an DesignTimeVisible attribute for the ViewController class and set the flag to false.
[System.ComponentModel.DesignTimeVisible(false)]
public partial class ViewController : UIViewController
After that, clean and rebuild the solutions. The screen should not showing in the Toolbox
‘s Custom Components section now. Also, it will no longer call into ViewDidLoad
method during design time. Adding the attribute to all the screens that defined in storyboard/xib solve the issue for now.