Search code examples
c#macosxamarinxibnsview

Getting System.InvalidCastException while loading View from a xib file


I have a xib file - LoaderView.xib and associated class LoaderView.cs which contains a view for showing loading text. When I try to load it in the main ViewController as -

public override void ViewDidAppear()
{
   base.ViewDidAppear();

   NSBundle.MainBundle.LoadNibNamed("LoaderView", this, out NSArray arr);
   var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
   view.Frame = View.Frame;
   View.AddSubview(view);
}

I am getting the System.InvalidCastException in this line -

var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));

And the strange part is I do not get the exception every time. When it works, I am seeing the loading text overlapped with default view - associated with the ViewController.

enter image description here

Can someone point out what is the best way to show Loading, Error and Empty states. Should I have separate ViewControllers for them? Or Can I have separate xib files which I can load/unload from the main View Controller? How to load a view from a xib file?


Solution

  • The problem lies within arr.

    enter image description here

    enter image description here

    In the above images, it can be seen that somehow the method LoadNibNamed is not returning the top level objects in arr in the same sequence every time. That's why the code -

    var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
    

    is not able to cast the 0th item of arr to type LoaderView every time.

    The solution is to traverse the array to find the item of your type - LoaderView here. For my case - I wrote a static class which has a generic method LoadViewFromNib which returns a view of type T inheriting from NSView.

    public static class LoadNib
    {
        static NSArray xibItems;
        static nuint index;
    
    
        public static T LoadViewFromNib<T>(string filename, NSObject owner) where T : NSView
        {
            NSBundle.MainBundle.LoadNibNamed(filename, owner, out xibItems);
    
            for (nuint i = 0; i < xibItems.Count; i++)
            {
                NSObject item = xibItems.GetItem<NSObject>(i);
                if (item is T)
                {
                    index = i;
                    break;
                }
            }
    
            return Runtime.GetNSObject<T>(xibItems.ValueAt(index));
        }
    }
    

    And as for the overlapping issue, I found out that a subview is transparent unless its background is set explicitly.