Skip to content

Instantly share code, notes, and snippets.

@albilaga
Created May 25, 2018 07:58
Show Gist options
  • Save albilaga/20a35ff32977c9bf32cd12ad5492e2cb to your computer and use it in GitHub Desktop.
Save albilaga/20a35ff32977c9bf32cd12ad5492e2cb to your computer and use it in GitHub Desktop.
Repeater View for Xamarin Forms
using System;
using System.Collections;
using System.Collections.Specialized;
using Xamarin.Forms;
namespace Pradana.CustomControls
{
public class RepeaterView : StackLayout
{
public RepeaterView()
{
this.Orientation = StackOrientation.Vertical;
}
#region Properties
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
propertyName: "ItemsSource",
returnType: typeof(IEnumerable),
declaringType: typeof(RepeaterView),
defaultValue: null,
defaultBindingMode: BindingMode.OneWay,
propertyChanged: ItemsChanged);
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
propertyName: "ItemTemplate",
returnType: typeof(DataTemplate),
declaringType: typeof(RepeaterView),
defaultValue: default(DataTemplate));
public event RepeaterViewItemAddedEventHandler ItemCreated;
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
#endregion
private static void ItemsChanged(BindableObject bindable, object oldValue, object newValue)
{
IEnumerable oldValueAsEnumerable;
IEnumerable newValueAsEnumerable;
try
{
oldValueAsEnumerable = oldValue as IEnumerable;
newValueAsEnumerable = newValue as IEnumerable;
}
catch (Exception e)
{
throw e;
}
var control = (RepeaterView)bindable;
var oldObservableCollection = oldValue as INotifyCollectionChanged;
if (oldObservableCollection != null)
{
oldObservableCollection.CollectionChanged -= control.OnItemsSourceCollectionChanged;
}
var newObservableCollection = newValue as INotifyCollectionChanged;
if (newObservableCollection != null)
{
newObservableCollection.CollectionChanged += control.OnItemsSourceCollectionChanged;
}
control.Children.Clear();
if (newValueAsEnumerable != null)
{
foreach (var item in newValueAsEnumerable)
{
var view = control.CreateChildViewFor(item);
control.Children.Add(view);
control.OnItemCreated(view);
}
}
control.UpdateChildrenLayout();
control.InvalidateLayout();
}
protected virtual void OnItemCreated(View view) =>
this.ItemCreated?.Invoke(this, new RepeaterViewItemAddedEventArgs(view, view.BindingContext));
private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var invalidate = false;
if (e.OldItems != null)
{
this.Children.RemoveAt(e.OldStartingIndex);
invalidate = true;
}
if (e.NewItems != null)
{
for (var i = 0; i < e.NewItems.Count; ++i)
{
var item = e.NewItems[i];
var view = this.CreateChildViewFor(item);
this.Children.Insert(i + e.NewStartingIndex, view);
OnItemCreated(view);
}
invalidate = true;
}
if (invalidate)
{
this.UpdateChildrenLayout();
this.InvalidateLayout();
}
}
private View CreateChildViewFor(object item)
{
this.ItemTemplate.SetValue(BindableObject.BindingContextProperty, item);
return (View)this.ItemTemplate.CreateContent();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment