Skip to content

Instantly share code, notes, and snippets.

@nmilcoff
Last active April 21, 2020 21:43
Show Gist options
  • Save nmilcoff/1bab04c2c07f9530244020b5dbde988e to your computer and use it in GitHub Desktop.
Save nmilcoff/1bab04c2c07f9530244020b5dbde988e to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using MvvmCross.Binding.Attributes;
using MvvmCross.Core.ViewModels;
using MvvmCross.Platform.WeakSubscription;
using UIKit;
namespace MvvmCross.StackView
{
public class MvxStackView<TView> : OAStackView.OAStackView
where TView : MvxView, new()
{
private IEnumerable<MvxNavigatingObject> itemsSource;
private MvxNotifyCollectionChangedEventSubscription subscription;
private IDictionary<MvxNavigatingObject, TView> itemsToViewsDictionary;
public MvxStackView(UILayoutConstraintAxis axis, float spacing)
{
this.Initialize(axis, spacing);
}
public MvxStackView(IntPtr handler)
: base(handler)
{
}
[MvxSetToNullAfterBinding]
public virtual IEnumerable<MvxNavigatingObject> ItemsSource
{
get { return this.itemsSource; }
set
{
if(ReferenceEquals(this.itemsSource, value))
return;
this.itemsSource = value;
var collectionChanged = this.itemsSource as INotifyCollectionChanged;
if(collectionChanged != null)
this.subscription = collectionChanged.WeakSubscribe(OnCollectionChanged);
InitializeContainer();
}
}
private void Initialize(UILayoutConstraintAxis axis, float spacing)
{
this.Axis = axis;
this.Spacing = spacing;
this.itemsToViewsDictionary = new Dictionary<MvxNavigatingObject, TView>();
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
if(this.subscription != null)
{
this.subscription.Dispose();
this.subscription = null;
}
}
base.Dispose(disposing);
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
var newItems = notifyCollectionChangedEventArgs?.NewItems;
if(newItems != null)
{
var newStartingIndex = notifyCollectionChangedEventArgs.NewStartingIndex;
foreach(var newItem in notifyCollectionChangedEventArgs.NewItems)
{
this.AddItemToStack(newItem as MvxNavigatingObject, newStartingIndex);
newStartingIndex++;
}
}
var oldItems = notifyCollectionChangedEventArgs?.OldItems;
if(oldItems != null)
{
foreach(var oldItem in notifyCollectionChangedEventArgs.OldItems)
this.RemoveItemFromStack(oldItem as MvxNavigatingObject);
}
}
private void InitializeContainer()
{
var index = 0;
this.itemsToViewsDictionary.Clear();
foreach(var viewModel in ItemsSource)
{
this.AddItemToStack(viewModel, index);
index++;
}
}
private void AddItemToStack(MvxNavigatingObject item, int index)
{
this.InvokeOnMainThread(() =>
{
if(index == -1)
index = 0;
var view = new TView();
if(view == null)
return;
view.DataContext = item;
this.itemsToViewsDictionary.Add(item, view);
this.OnBeforeAdd(view);
this.InsertArrangedSubview(view, (nuint)index);
this.OnAfterAdd(view);
});
}
private void RemoveItemFromStack(MvxNavigatingObject item)
{
this.InvokeOnMainThread(() =>
{
if(!this.itemsToViewsDictionary.ContainsKey(item))
return;
var view = this.itemsToViewsDictionary[item];
this.OnBeforeRemove(view);
this.RemoveArrangedSubview(view);
view.RemoveFromSuperview();
this.itemsToViewsDictionary.Remove(item);
this.OnAfterRemove(view);
});
}
#region lifecycle callbacks
protected virtual void OnBeforeAdd(UIView view)
{
}
protected virtual void OnAfterAdd(UIView view)
{
}
protected virtual void OnBeforeRemove(UIView view)
{
}
protected virtual void OnAfterRemove(UIView view)
{
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment