1

For the first time I'm trying to make use of section headers in a UICollectionView in Xamarin.iOS following the Microsoft Guide and some other resources. When the UICollectionView loads a section header, all outlets connected to the view of the section header are null, resulting in a NullReferenceException.

Out of curiosity I removed all outlets but ran into the following exception: ObjCRuntime.ObjCException: Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath: was not retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: for element kind 'UICollectionElementKindSectionHeader' at index path ... This one confuses me because I do call the specified method for returning the view.

I searched for this exception and found similar problems without any accepted answers such as this one: Similar Problem in Swift

Here are my classes:

MyViewController containing the UICollectionView:

MyDataSource dataSource = new MyDataSource();
dataSource.SetData(...);

// NOTE: RegisterClassForCell and RegisterClassForSupplementaryView don't work. When I do call these methode the cells/ views are not loaded (AwakeFromNib is never called).
MyCollectionView.RegisterNibForCell(UINib.FromName(nameof(MyCollectionViewCell), null), MyCollectionViewCell.ReuseIdentifier);
MyCollectionView.RegisterNibForSupplementaryView(UINib.FromName(nameof(MyCollectionViewSectionHeader), null), UICollectionElementKindSection.Header, MyCollectionViewSectionHeader.SectionIdentifier);

MyCollectionView.DataSource = dataSource;
MyCollectionView.ReloadData();

        
MyCollectionView.CollectionViewLayout = new UICollectionViewFlowLayout
{
    ScrollDirection = UICollectionViewScrollDirection.Vertical,
    // 2 items per row
    ItemSize = new CGSize(width, height),
    MinimumInteritemSpacing = spacing,
    MinimumLineSpacing = spacing,
    HeaderReferenceSize = new CGSize(width, height)
};

MyDataSource with the code for returning the supplementary views

public class MyDataSource : UICollectionViewSource
{
    public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
    {
        var section =  (MyCollectionViewSectionHeader)collectionView.DequeueReusableSupplementaryView(elementKind, _sectionId, indexPath);
        section.SectionLoaded(_sectionData);
        return section;
    }
    ...    
}

MyCollectionViewSectionHeader (the view that fails to load)

public partial class MyCollectionViewSectionHeader: UICollectionReusableView
{
    public void SectionLoaded(MyCollectionViewSectionData data)
    {
        // NullReferenceException here 
        LblTitle.Text = data.Title;
    }
    ...
}

Any hints on what I am doing wrong? Thank you for any help.

ben_bekir
  • 121
  • 1
  • 10
  • ```RegisterClassForCell``` and ```RegisterClassForSupplementaryView``` method should work. Does GetCell or GetViewForSupplementaryElement get called? – Liqun Shen-MSFT Jun 20 '23 at 14:16
  • Have you added the ```View.AddSubview(MyCollectionView);``` in ViewDidLoad of ```MyViewController``` – Liqun Shen-MSFT Jun 20 '23 at 14:23
  • @LiqunShen-MSFT I have tested everything some more yesterday and it turns out that `RegisterClassForSupplementaryView` and `RegisterClassForCell` only work when their Views don't have a nib/ xib-file associated to them. I was able to make the section header appear by calling `RegisterClassForSupplementaryView` for a class which constructor was annotated with `[Export ("initWithFrame:")]`. But since the class/ view doesn't use a xib, I had to set the ui controls (like labels) programmatically. I will test out a bit more today and maybe tomorrow and see if I can make it work with a nib. – ben_bekir Jun 21 '23 at 09:51
  • May I ask if you still meet this issue? – Liqun Shen-MSFT Jun 24 '23 at 10:03
  • @LiqunShen-MSFT yes, unfortunately my issue still exists. However, the "workaround" with `RegisterClassForSupplementaryView` works just fine. I would still be thankful for a solution that enables me to use the `RegisterNibForSupplementaryView` method so that I can properly use the xcode interface builder. – ben_bekir Jun 26 '23 at 20:29

1 Answers1

0

You could try the following way for SupplementaryView.

1.Create a new Class inherit UICollectionReusableView.(I create a uicollectionviewcell first, then change inherit to UICollectionReusableView)

public partial class MyHeaderCell : UICollectionReusableView
{

    public static readonly UINib Nib;

    static MyHeaderCell()
    {
        Nib = UINib.FromName("MyCustomCell", NSBundle.MainBundle);
    }

    protected MyHeaderCell (IntPtr handle) : base (handle)
    {
        // Note: this .ctor should not contain any initialization logic.
    }
}

in ViewController, register it,

 MyCollectionView.RegisterNibForSupplementaryView(UINib.FromName("MyHeaderCell", NSBundle.MainBundle), UICollectionElementKindSection.Header, "headercells");

in datasource:

public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
{
    MyHeaderCell headerView = (MyHeaderCell)collectionView.DequeueReusableSupplementaryView(elementKind, "headercells", indexPath);
    
    // this probably depend on the UI you defined in xib, I just put a label in headerview, so I get the label through this way
    UILabel label =  headerView.Subviews[0].Subviews[0] as UILabel;
    label.Text = "My Supplementary View";
    return headerView;
}

Hope it helps!

Liqun Shen-MSFT
  • 3,490
  • 2
  • 3
  • 11