Skip to content

Instantly share code, notes, and snippets.

@slodge
Last active January 31, 2017 04:47
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save slodge/6070386 to your computer and use it in GitHub Desktop.
Save slodge/6070386 to your computer and use it in GitHub Desktop.
// an abstract helper class
public abstract class MvxAnnotationManager
{
private readonly MKMapView _mapView;
private IEnumerable _itemsSource;
private IDisposable _subscription;
public Dictionary<object, MKAnnotation> _annotations = new Dictionary<object, MKAnnotation>();
protected MvxAnnotationManager(MKMapView mapView)
{
_mapView = mapView;
}
// MvxSetToNullAfterBinding isn't strictly needed any more
// - but it's nice to have for when binding is torn down
[MvxSetToNullAfterBinding]
public virtual IEnumerable ItemsSource
{
get { return _itemsSource; }
set { SetItemsSource(value); }
}
protected virtual void SetItemsSource(IEnumerable value)
{
if (_itemsSource == value)
return;
if (_subscription != null)
{
_subscription.Dispose();
_subscription = null;
}
_itemsSource = value;
if (_itemsSource != null && !(_itemsSource is IList))
MvxBindingTrace.Trace(MvxTraceLevel.Warning,
"Binding to IEnumerable rather than IList - this can be inefficient, especially for large lists");
ReloadAllAnnotations();
var newObservable = _itemsSource as INotifyCollectionChanged;
if (newObservable != null)
{
_subscription = newObservable.WeakSubscribe(OnItemsSourceCollectionChanged);
}
}
protected virtual void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
AddAnnotations(e.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
RemoveAnnotations(e.OldItems);
break;
case NotifyCollectionChangedAction.Replace:
RemoveAnnotations(e.OldItems);
AddAnnotations(e.NewItems);
break;
case NotifyCollectionChangedAction.Move:
// not interested in this
break;
case NotifyCollectionChangedAction.Reset:
ReloadAllAnnotations();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
protected virtual void ReloadAllAnnotations()
{
_mapView.RemoveAnnotations(_annotations.Values.Select(x => (NSObject)x).ToArray());
_annotations.Clear();
if (_itemsSource == null)
return;
AddAnnotations(_itemsSource);
}
protected abstract MKAnnotation CreateAnnotation(object item);
protected virtual void RemoveAnnotations(IEnumerable oldItems)
{
foreach (var item in oldItems)
{
RemoveAnnotationFor(item);
}
}
protected virtual void RemoveAnnotationFor(object item)
{
var annotation = _annotations[item];
_mapView.RemoveAnnotation(annotation);
_annotations.Remove(item);
}
protected virtual void AddAnnotations(IEnumerable newItems)
{
foreach (object item in newItems)
{
AddAnnotationFor(item);
}
}
protected virtual void AddAnnotationFor(object item)
{
var annotation = CreateAnnotation(item);
_annotations[item] = annotation;
_mapView.AddAnnotation(annotation);
}
}
// example use
public class House
{
public double Lat { get; set; }
public double Lng { get; set; }
public string Name { get; set; }
}
public class FirstViewModel : MvxViewModel
{
public ObservableCollection<House> Houses { get; set; }
}
public class HouseAnnotationManager
: MvxAnnotationManager
{
public HouseAnnotationManager(MKMapView mapView) : base(mapView)
{
}
protected override MKAnnotation CreateAnnotation(object item)
{
var house = item as House;
return new HouseAnnotation(item);
}
}
public class HouseAnnotation : MKAnnotation
{
public HouseAnnotation(House house)
{
// use house here...
// in theory you could also data-bind to the house too (e.g. if it's location were to move...)
}
public override CLLocationCoordinate2D Coordinate { get; set; }
}
[Register("FirstView")]
public class FirstView : MvxViewController
{
private HouseAnnotationManager _manager;
public override void ViewDidLoad()
{
View = new UIView(){ BackgroundColor = UIColor.White};
base.ViewDidLoad();
var myMapView = new MKMapView(View.Frame);
Add(myMapView);
myMapView.Delegate = new MyMapDelegate(); // standard map delegate - must provide the annotation views
_manager = new HouseAnnotationManager(myMapView);
var set = this.CreateBindingSet<FirstView, FirstViewModel>();
set.Bind(_manager).For(m => m.ItemsSource).To(vm => vm.HouseList);
set.Apply();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment