-
-
Save NVentimiglia/2723411428cdbb72fac6 to your computer and use it in GitHub Desktop.
// MIT License | |
// Nicholas Ventimiglia | |
// 2016-9-19 | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Collections.ObjectModel; | |
using System.Collections.Specialized; | |
using System.Linq; | |
using System.Windows.Input; | |
using Xamarin.Forms; | |
/// <summary> | |
/// For repeated content without a automatic scroll view. Supports DataTemplates, Horizontal and Vertical layouts ! | |
/// </summary> | |
/// <remarks> | |
/// Warning TODO NO Visualization or Paging! Handle this in your view model. | |
/// </remarks> | |
public class ItemsStack : StackLayout | |
{ | |
#region BindAble | |
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create<ItemsStack, IEnumerable>(p => p.ItemsSource, default(IEnumerable<object>), BindingMode.TwoWay, null, ItemsSourceChanged); | |
public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create<ItemsStack, object>(p => p.SelectedItem, default(object), BindingMode.TwoWay, null, OnSelectedItemChanged); | |
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create<ItemsStack, DataTemplate>(p => p.ItemTemplate, default(DataTemplate)); | |
public event EventHandler<SelectedItemChangedEventArgs> SelectedItemChanged; | |
public IEnumerable ItemsSource | |
{ | |
get { return (IEnumerable)GetValue(ItemsSourceProperty); } | |
set { SetValue(ItemsSourceProperty, value); } | |
} | |
public object SelectedItem | |
{ | |
get { return GetValue(SelectedItemProperty); } | |
set { SetValue(SelectedItemProperty, value); } | |
} | |
public DataTemplate ItemTemplate | |
{ | |
get { return (DataTemplate)GetValue(ItemTemplateProperty); } | |
set { SetValue(ItemTemplateProperty, value); } | |
} | |
private static void ItemsSourceChanged(BindableObject bindable, IEnumerable oldValue, IEnumerable newValue) | |
{ | |
var itemsLayout = (ItemsStack)bindable; | |
itemsLayout.SetItems(); | |
} | |
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue) | |
{ | |
var itemsView = (ItemsStack)bindable; | |
if (newValue == oldValue) | |
return; | |
itemsView.SetSelectedItem(newValue); | |
} | |
#endregion | |
#region item rendering | |
protected readonly ICommand ItemSelectedCommand; | |
protected virtual void SetItems() | |
{ | |
Children.Clear(); | |
if (ItemsSource == null) | |
{ | |
ObservableSource = null; | |
return; | |
} | |
foreach (var item in ItemsSource) | |
Children.Add(GetItemView(item)); | |
var isObs = ItemsSource.GetType().IsGenericType && ItemsSource.GetType().GetGenericTypeDefinition() == typeof(ObservableCollection<>); | |
if (isObs) | |
{ | |
ObservableSource = new ObservableCollection<object>(ItemsSource.Cast<object>()); | |
} | |
} | |
protected virtual View GetItemView(object item) | |
{ | |
var content = ItemTemplate.CreateContent(); | |
var view = content as View; | |
if (view == null) | |
return null; | |
view.BindingContext = item; | |
var gesture = new TapGestureRecognizer | |
{ | |
Command = ItemSelectedCommand, | |
CommandParameter = item | |
}; | |
AddGesture(view, gesture); | |
return view; | |
} | |
protected void AddGesture(View view, TapGestureRecognizer gesture) | |
{ | |
view.GestureRecognizers.Add(gesture); | |
var layout = view as Layout<View>; | |
if (layout == null) | |
return; | |
foreach (var child in layout.Children) | |
AddGesture(child, gesture); | |
} | |
protected virtual void SetSelectedItem(object selectedItem) | |
{ | |
var handler = SelectedItemChanged; | |
if (handler != null) | |
handler(this, new SelectedItemChangedEventArgs(selectedItem)); | |
} | |
ObservableCollection<object> _observableSource; | |
protected ObservableCollection<object> ObservableSource | |
{ | |
get { return _observableSource; } | |
set | |
{ | |
if (_observableSource != null) | |
{ | |
_observableSource.CollectionChanged -= CollectionChanged; | |
} | |
_observableSource = value; | |
if (_observableSource != null) | |
{ | |
_observableSource.CollectionChanged += CollectionChanged; | |
} | |
} | |
} | |
private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) | |
{ | |
switch (e.Action) | |
{ | |
case NotifyCollectionChangedAction.Add: | |
{ | |
int index = e.NewStartingIndex; | |
foreach (var item in e.NewItems) | |
Children.Insert(index++, GetItemView(item)); | |
} | |
break; | |
case NotifyCollectionChangedAction.Move: | |
{ | |
var item = ObservableSource[e.OldStartingIndex]; | |
Children.RemoveAt(e.OldStartingIndex); | |
Children.Insert(e.NewStartingIndex, GetItemView(item)); | |
} | |
break; | |
case NotifyCollectionChangedAction.Remove: | |
{ | |
Children.RemoveAt(e.OldStartingIndex); | |
} | |
break; | |
case NotifyCollectionChangedAction.Replace: | |
{ | |
Children.RemoveAt(e.OldStartingIndex); | |
Children.Insert(e.NewStartingIndex, GetItemView(ObservableSource[e.NewStartingIndex])); | |
} | |
break; | |
case NotifyCollectionChangedAction.Reset: | |
Children.Clear(); | |
foreach (var item in ItemsSource) | |
Children.Add(GetItemView(item)); | |
break; | |
} | |
} | |
#endregion | |
public ItemsStack() | |
{ | |
ItemSelectedCommand = new Command<object>(item => | |
{ | |
SelectedItem = item; | |
}); | |
} | |
} |
when i am using this itemStack , it does not have scrolling functionality and when i put that in scroll it does not scroll .
I encounter an problem on this line:
var isObs = ItemsSource.GetType().IsGenericType && ItemsSource.GetType().GetGenericTypeDefinition() == typeof(ObservableCollection<>);
I get the following error:
'Type' does not contain a definition for 'IsGenericType' and no extension method 'IsGenericType' accepting a first argument of type 'Type' could be found (are you missing a using directive or an assembly reference?)
Any idea?
None of this joins up, the original class and all the edits are incomplete unfortunately. Writing my own, thanks anyway.
I uses a modified version of it for some extra feature, it was working all good until I upgraded my Xamarin.Forms version.
I gets null pointer exception over var content = ItemTemplate.CreateContent();
Anyone got the same issue or someone got a fix for it?
previous XF V - 2.3
current XF V - 4.2 (Forcefully needed to upgrade it cuz of iOS13 iPad issue with masterPage)
@bmasis @barryculhane @luismts
Chuck this in SetItems (and you can remove ObservableSource). Should allow CollectionChanged to trigger (my issue at least was that it wasn't triggering for adding/removing elements from my ObservableCollection).