mrtnkrstn
mrtnkrstn

Reputation: 316

MvxCollectionViewController with Sections

Using Xamarin.iOS and MvvmCross, I am trying to create an MvxCollectionViewController that contains Sections, with each Section consisting of a title and a collection of MvxCollectionViewCell (based on the MvvmCross tutorial http://slodge.blogspot.co.uk/2013/05/n11-collectionview-n1-days-of-mvvmcross.html).

I have subclassed MvxCollectionViewCell as set out in the tutorial. I have the following Model and ViewModel hierarchy (adapted from the tutorial):

public class Kitten    
{
    public string Name { get; set; }
    public string ImageUrl { get; set; }
}

the ViewModel for each Section:

public class KittenSectionViewModel : MvxViewModel
{
    private string _sectionName;
    public string SectionName
    {
        get { return _sectionName; }
        set { _sectionName = value; RaisePropertyChanged(() => SectionName); }
    }

    private List<Kitten> _kittens;
    public List<Kitten> Kittens
    { 
        get { return _kittens; }
        set { _kittens = value; RaisePropertyChanged(() => Kittens); }
    }
}

and then the ViewModel for all the Sections:

public class KittensViewModel: MvxViewModel
{
    private readonly IKittenService _kittenService;

    public List<KittenSectionViewModel> KittenSections { get; set; }

    public KittensViewModel(IKittenService kittenService)
    {
        _kittenService = kittenService;
    }

    public override void Start ()
    {
        KittenSections = _kittenService.GetKittens().ToList();
    }
}

The KittenCollectionCell is basically unchanged:

public KittenCollectionCell (IntPtr handle) : base (handle)
{
    _loader = new MvxImageViewLoader(() => MainImage);

    this.DelayBind(() => {
        var set = this.CreateBindingSet<KittenCollectionCell, Kitten>();
        set.Bind(NameLabel).To(kitten => kitten.Name);
        set.Bind (_loader).To (kitten => kitten.ImageUrl);
        set.Apply();
    });
}

And lastly I have implemented a custom MvxCollectionViewSource, which I assign to the CollectionView's Source:

public class KittenCollectionViewSource : MvxCollectionViewSource
{
    KittensViewModel KittensViewModel { get; set; }

    public KittenCollectionViewSource (KittensViewModel kittensViewModel, UICollectionView collectionView, NSString defaultCellIdentifier) : base (collectionView, defaultCellIdentifier)
    {
        this.KittensViewModel = kittensViewModel;
    }

    public override int GetItemsCount (UICollectionView collectionView, int section)
    {
        return KittensViewModel.KittenSections [section].Kittens.Count;
    }

    public override int NumberOfSections (UICollectionView collectionView)
    {
        return KittensViewModel.KittenSections.Count;
    }

    protected override UICollectionViewCell GetOrCreateCellFor (UICollectionView collectionView, NSIndexPath indexPath, object item)
    {
        return collectionView.DequeueReusableCell (DefaultCellIdentifier, indexPath) as KittenCollectionCell;
    }
}

(The full solution is available at https://github.com/mrtnkrstn/SectionedKittenCollectionView.git).

The problem is that the KittenCollectionCell needs to bind to a Kitten, but because the model is wrapped inside a different viewmodel, I don't know how to tell the MvxCollectionViewSource to use the inner model?

Upvotes: 1

Views: 1251

Answers (1)

Stuart
Stuart

Reputation: 66882

The structure of your source looks fairly simple - so I think all you are missing is the GetItemAt override - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxCollectionViewSource.cs#L75

I think you'll need to add something like:

    protected override object GetItemAt(NSIndexPath indexPath)
    {
        if (KittensViewModel == null)
            return null;

        return KittensViewModel
                      .KittenSections[indexPath.Section]
                      .Kittens[indexPath.Row];
    }

You might also be able to implement KittensViewModel as:

   protected KittensViewModel KittensViewModel { get { return base.ItemsSource as KittensViewModel; } }

Upvotes: 3

Related Questions