1

I am trying to set global variables such as colour in my app. Namely the navigation bar, the colours for which I am having to set individually in each view controller. I have created a helper class, UIHelper.cs to set these values and then call them elsewhere. In my MainViewController.cs, I am creating an instance of UIHelper and calling it in this line: this.NavigationController.NavigationBar.BarTintColor = uiHelper.SetNavBarRGB();

But this is throwing a System.NullReferenceException.

System.NullReferenceException: Object reference not set to an instance of an object
  at NoteTaker.iOS.MainViewController.ViewDidLoad () [0x00018] in /Users/richardcurteis/Development/XamarinProjects/NoteTaker/iOS/MainViewController_.cs:28
  at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/2377/73229919/source/maccore/src/UIKit/UIApplication.cs:77
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/2377/73229919/source/maccore/src/UIKit/UIApplication.cs:61
  at NoteTaker.iOS.Application.Main (System.String[] args) [0x00013] in /Users/richardcurteis/Development/XamarinProjects/NoteTaker/iOS/Main.cs:17

MainViewController.cs

using System;
using System.CodeDom.Compiler;
using UIKit;
using System.Collections.Generic;

namespace NoteTaker.iOS
{
    partial class MainViewController : UIViewController
    {
        List<Note> notes;
        UITableView table;
        UIHelper uiHelper;


        public MainViewController (IntPtr handle) : base (handle)
        {
            notes = new List<Note> ();
            UIHelper uiHelper = new UIHelper();
        }

        public override void ViewDidLoad ()

        {
            base.ViewDidLoad ();

            //this.NavigationController.NavigationBar.BarTintColor = UIColor.FromRGB (255,0,255);
            this.NavigationController.NavigationBar.BarTintColor = uiHelper.SetNavBarRGB(); // Exception being thrown here
            this.Title = "Notes";
            this.NavigationController.NavigationBar.TitleTextAttributes = new UIStringAttributes () { ForegroundColor = UIColor.White };

            table = new UITableView () {
                Frame = new CoreGraphics.CGRect (0, this.NavigationController.NavigationBar.Frame.Bottom, this.View.Bounds.Width, this.View.Bounds.Height - this.NavigationController.NavigationBar.Frame.Height),
            };
            this.View.Add (table);

            var addButton = new UIBarButtonItem (UIBarButtonSystemItem.Add);
            addButton.TintColor = UIColor.White;

            this.NavigationItem.RightBarButtonItems = new UIBarButtonItem[] { addButton };
            addButton.Clicked += (sender, e) => {
                this.NavigationController.PushViewController (new NoteViewController(), true);
            };

            notes = Database.getNotes ();
            table.Source = new NotesTableViewSource (notes, this);
        }

        public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);
            notes = Database.getNotes ();
            table.Source = new NotesTableViewSource(notes, this );
        }
    }
}

UIHelper.cs

using System;
using UIKit;

namespace NoteTaker.iOS
{
    public class UIHelper : UIInputViewController
    {
        public UIHelper ()
        {
        }

        public UIColor SetNavBarRGB ()
        {
            var uiColour = UIColor.FromRGB (255, 0, 255);
            return uiColour;
        }
    }
}

2 Answers 2

2

You have a conflict:

You declare uiHelper as a field in the class definition:

partial class MainViewController : UIViewController
{
    List<Note> notes;
    UITableView table;
    UIHelper uiHelper;

and then in the constructor you declare another variable with the same name:

public MainViewController (IntPtr handle) : base (handle)
{
        notes = new List<Note> ();
        UIHelper uiHelper = new UIHelper();
}

This causes a local uiHelper to be declared and assigned within the scope of the constructor only, but the class' field uiHelper is never touched. Hence it is null in the ViewLoad()method. Just remove the type in the constructor and you'll be fine:

public MainViewController (IntPtr handle) : base (handle)
{
        notes = new List<Note> ();
        uiHelper = new UIHelper();
}
Sign up to request clarification or add additional context in comments.

Comments

1

Does you MainViewController Constructor (MainViewController (IntPtr handle)) even gets called?

Can you try checking against null for uiHelper variable, and if it is null, then initializing a new instance from UIHelper class.

 public override void ViewDidLoad ()

        {
            base.ViewDidLoad ();
             If(uiHelper == null)
             {
                 uiHelper = new UIHelper(); 
             }
            //this.NavigationController.NavigationBar.BarTintColor = UIColor.FromRGB (255,0,255);
            this.NavigationController.NavigationBar.BarTintColor = uiHelper.SetNavBarRGB(); // Exception being thrown here
            this.Title = "Notes";
            this.NavigationController.NavigationBar.TitleTextAttributes = new UIStringAttributes () { ForegroundColor = UIColor.White };

            table = new UITableView () {
                Frame = new CoreGraphics.CGRect (0, this.NavigationController.NavigationBar.Frame.Bottom, this.View.Bounds.Width, this.View.Bounds.Height - this.NavigationController.NavigationBar.Frame.Height),
            };
            this.View.Add (table);

            var addButton = new UIBarButtonItem (UIBarButtonSystemItem.Add);
            addButton.TintColor = UIColor.White;

            this.NavigationItem.RightBarButtonItems = new UIBarButtonItem[] { addButton };
            addButton.Clicked += (sender, e) => {
                this.NavigationController.PushViewController (new NoteViewController(), true);
            };

            notes = Database.getNotes ();
            table.Source = new NotesTableViewSource (notes, this);
        }

2 Comments

That's a very good point. A .ctor(IntPtr) is called when an existing native instance is surfaced to the managed side. It's rarely a good place to put initialization code and, if created by managed code only, it might never be called. For subclasses of native types it's better to look at their life cycle (e.g. UIView and UIViewController are well documented) as it often makes it clear when you can do some things (and when it's too early or too late to do them).
@poupou, what would you suggest as an alternative?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.