Skip to content

Instantly share code, notes, and snippets.

@tsjdev-apps
Created November 24, 2018 21:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsjdev-apps/2024d6b40ad3877c63062947941b8cd5 to your computer and use it in GitHub Desktop.
Save tsjdev-apps/2024d6b40ad3877c63062947941b8cd5 to your computer and use it in GitHub Desktop.
Xamarin.Forms Controls: RepeaterView
[ContentProperty(nameof(ItemTemplate))]
public class RepeaterView : StackLayout
{
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create(nameof(ItemsSource), typeof(ICollection), typeof(RepeaterView), propertyChanged: ItemsSourcePropertyOnChanged);
public ICollection ItemsSource
{
get => (ICollection)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(RepeaterView), default(DataTemplate));
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
public static readonly BindableProperty ItemTappedCommandProperty =
BindableProperty.Create(nameof(ItemTappedCommand), typeof(ICommand), typeof(RepeaterView));
public ICommand ItemTappedCommand
{
get => GetValue(ItemTappedCommandProperty) as ICommand;
set => SetValue(ItemTappedCommandProperty, value);
}
public RepeaterView()
{
Spacing = 0;
}
protected virtual View ViewFor(object item)
{
if (ItemTemplate == null)
return null;
var content = ItemTemplate.CreateContent();
var view = content is ViewCell viewCell ? viewCell.View : content as View;
view.BindingContext = item;
if (ItemTappedCommand != null)
AddTapGestureToChildView(view);
return view;
}
private static void ItemsSourcePropertyOnChanged(BindableObject bindable, object oldValue, object newValue)
{
if (!(bindable is RepeaterView control))
return;
control.Children.Clear();
var collection = (ICollection)newValue;
if (collection == null)
return;
if (collection is INotifyCollectionChanged observableCollection)
control.AddCollectionNotificationsListener(observableCollection);
foreach (var item in collection)
control.Children.Add(control.ViewFor(item));
}
private void AddCollectionNotificationsListener(INotifyCollectionChanged observableCollection)
{
if (observableCollection == null)
throw new ArgumentNullException(nameof(observableCollection));
observableCollection.CollectionChanged -= ObsersavableCollectionOnCollectionChanged;
observableCollection.CollectionChanged += ObsersavableCollectionOnCollectionChanged;
}
private void ObsersavableCollectionOnCollectionChanged(object s, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var newItem in e.NewItems)
Children.Add(ViewFor(newItem));
break;
case NotifyCollectionChangedAction.Remove:
foreach (var oldItem in e.OldItems)
{
var viewToRemove = Children.FirstOrDefault(x => x.BindingContext == oldItem);
if (viewToRemove != null)
Children.Remove(viewToRemove);
}
break;
default:
Children.Clear();
foreach (var item in (ICollection)s)
Children.Add(ViewFor(item));
break;
}
}
private void AddTapGestureToChildView(View view)
{
if (view == null)
throw new ArgumentNullException(nameof(view));
view.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() =>
{
if (ItemTappedCommand.CanExecute(view.BindingContext))
ItemTappedCommand.Execute(view.BindingContext);
})
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment