/// Selectable RecyclerView that presenting a collection of items with variable layouters.
/// </summary>
/// <since_tizen> 9 </since_tizen>
- public class CollectionView : RecyclerView
+ public partial class CollectionView : RecyclerView
{
/// <summary>
/// Binding Property of selected item in single selection.
BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(CollectionView), null,
propertyChanged: (bindable, oldValue, newValue) =>
{
- var colView = (CollectionView)bindable;
+ var colView = bindable as CollectionView;
+ if (colView == null)
+ {
+ throw new Exception("Bindable object is not CollectionView.");
+ }
+
oldValue = colView.selectedItem;
colView.selectedItem = newValue;
var args = new SelectionChangedEventArgs(oldValue, newValue);
foreach (RecyclerViewItem item in colView.ContentContainer.Children.Where((item) => item is RecyclerViewItem))
{
- if (item.BindingContext == null) continue;
- if (item.BindingContext == oldValue) item.IsSelected = false;
- else if (item.BindingContext == newValue) item.IsSelected = true;
+ if (item.BindingContext == null)
+ {
+ continue;
+ }
+
+ if (item.BindingContext == oldValue)
+ {
+ item.IsSelected = false;
+ }
+ else if (item.BindingContext == newValue)
+ {
+ item.IsSelected = true;
+ }
}
SelectionPropertyChanged(colView, args);
},
defaultValueCreator: (bindable) =>
{
- var colView = (CollectionView)bindable;
+ var colView = bindable as CollectionView;
+ if (colView == null)
+ {
+ throw new Exception("Bindable object is not CollectionView.");
+ }
+
return colView.selectedItem;
});
BindableProperty.Create(nameof(SelectedItems), typeof(IList<object>), typeof(CollectionView), null,
propertyChanged: (bindable, oldValue, newValue) =>
{
- var colView = (CollectionView)bindable;
+ var colView = bindable as CollectionView;
+ if (colView == null)
+ {
+ throw new Exception("Bindable object is not CollectionView.");
+ }
+
var oldSelection = colView.selectedItems ?? selectEmpty;
//FIXME : CoerceSelectedItems calls only isCreatedByXaml
var newSelection = (SelectionList)CoerceSelectedItems(colView, newValue);
},
defaultValueCreator: (bindable) =>
{
- var colView = (CollectionView)bindable;
+ var colView = bindable as CollectionView;
+ if (colView == null)
+ {
+ throw new Exception("Bindable object is not CollectionView.");
+ }
+
colView.selectedItems = colView.selectedItems ?? new SelectionList(colView);
return colView.selectedItems;
});
BindableProperty.Create(nameof(SelectionMode), typeof(ItemSelectionMode), typeof(CollectionView), ItemSelectionMode.None,
propertyChanged: (bindable, oldValue, newValue) =>
{
- var colView = (CollectionView)bindable;
+ var colView = bindable as CollectionView;
+ if (colView == null)
+ {
+ throw new Exception("Bindable object is not CollectionView.");
+ }
+
oldValue = colView.selectionMode;
colView.selectionMode = (ItemSelectionMode)newValue;
SelectionModePropertyChanged(colView, oldValue, newValue);
},
defaultValueCreator: (bindable) =>
{
- var colView = (CollectionView)bindable;
- return colView.selectionMode;
- });
-
- /// <summary>
- /// Binding Property of items data source.
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static readonly BindableProperty ItemsSourceProperty =
- BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(CollectionView), null,
- propertyChanged: (bindable, oldValue, newValue) =>
- {
- var colView = (CollectionView)bindable;
- oldValue = colView.itemsSource;
-
- if (oldValue != null)
+ var colView = bindable as CollectionView;
+ if (colView == null)
{
- // Clearing old data!
- if (oldValue is INotifyCollectionChanged prevNotifyCollectionChanged)
- {
- prevNotifyCollectionChanged.CollectionChanged -= colView.CollectionChanged;
- }
- if (colView.selectedItem != null) colView.selectedItem = null;
- colView.selectedItems?.Clear();
+ throw new Exception("Bindable object is not CollectionView.");
}
- colView.itemsSource = (IEnumerable)newValue;
-
- if (newValue == null)
- {
- colView.InternalItemSource?.Dispose();
- colView.InternalItemSource = null;
- colView.itemsLayouter?.Clear();
- colView.ClearCache();
- return;
- }
- if (newValue is INotifyCollectionChanged newNotifyCollectionChanged)
- {
- newNotifyCollectionChanged.CollectionChanged += colView.CollectionChanged;
- }
-
- colView.InternalItemSource?.Dispose();
- colView.InternalItemSource = ItemsSourceFactory.Create(colView);
-
- if (colView.itemsLayouter == null) return;
-
- colView.needInitalizeLayouter = true;
- colView.Init();
- },
- defaultValueCreator: (bindable) =>
- {
- var colView = (CollectionView)bindable;
- return colView.itemsSource;
+ return colView.selectionMode;
});
private ItemSelectionMode selectionMode = ItemSelectionMode.None;
private RecyclerViewItem header;
private RecyclerViewItem footer;
- private View focusedView;
- private int prevFocusedDataIndex = 0;
private List<RecyclerViewItem> recycleGroupHeaderCache { get; } = new List<RecyclerViewItem>();
private List<RecyclerViewItem> recycleGroupFooterCache { get; } = new List<RecyclerViewItem>();
private bool delayedScrollTo;
private bool delayedIndexScrollTo;
private (int index, bool anim, ItemScrollTo scrollTo) delayedIndexScrollToParam;
+ private void Initialize()
+ {
+ FocusGroup = true;
+ SetKeyboardNavigationSupport(true);
+ }
+
/// <summary>
/// Base constructor.
/// </summary>
/// <since_tizen> 9 </since_tizen>
public CollectionView() : base()
{
- FocusGroup = true;
- SetKeyboardNavigationSupport(true);
+ Initialize();
}
/// <summary>
}
/// <summary>
+ /// Creates a new instance of a CollectionView with style.
+ /// </summary>
+ /// <param name="style">A style applied to the newly created CollectionView.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public CollectionView(ControlStyle style) : base(style)
+ {
+ Initialize();
+ }
+
+ /// <summary>
/// Event of Selection changed.
/// previous selection list and current selection will be provided.
/// </summary>
/// <since_tizen> 9 </since_tizen>
public override IEnumerable ItemsSource
{
- get => (IEnumerable)GetValue(ItemsSourceProperty);
- set => SetValue(ItemsSourceProperty, value);
+ get => GetValue(RecyclerView.ItemsSourceProperty) as IEnumerable;
+ set => SetValue(RecyclerView.ItemsSourceProperty, value);
+ }
+
+ internal override IEnumerable InternalItemsSource
+ {
+ get
+ {
+ return itemsSource;
+ }
+ set
+ {
+ if (itemsSource != null)
+ {
+ // Clearing old data!
+ if (itemsSource is INotifyCollectionChanged prevNotifyCollectionChanged)
+ {
+ prevNotifyCollectionChanged.CollectionChanged -= CollectionChanged;
+ }
+ if (selectedItem != null)
+ {
+ selectedItem = null;
+ }
+ selectedItems?.Clear();
+ }
+
+ itemsSource = value as IEnumerable;
+
+ if (itemsSource == null)
+ {
+ InternalItemSource?.Dispose();
+ InternalItemSource = null;
+ itemsLayouter?.Clear();
+ ClearCache();
+ return;
+ }
+ if (itemsSource is INotifyCollectionChanged newNotifyCollectionChanged)
+ {
+ newNotifyCollectionChanged.CollectionChanged += CollectionChanged;
+ }
+
+ InternalItemSource?.Dispose();
+ InternalItemSource = ItemsSourceFactory.Create(this);
+
+ if (itemsLayouter == null) return;
+
+ needInitalizeLayouter = true;
+ ReinitializeLayout();
+
+ }
}
/// <summary>
{
get
{
+ return GetValue(ItemTemplateProperty) as DataTemplate;
+ }
+ set
+ {
+ SetValue(ItemTemplateProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ internal override DataTemplate InternalItemTemplate
+ {
+ get
+ {
return itemTemplate;
}
set
}
needInitalizeLayouter = true;
- Init();
+ ReinitializeLayout();
}
}
{
get
{
+ return GetValue(ItemsLayouterProperty) as ItemsLayouter;
+ }
+ set
+ {
+ SetValue(ItemsLayouterProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+
+
+ /// <inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override ItemsLayouter InternalItemsLayouter
+ {
+ get
+ {
return itemsLayouter;
}
set
{
itemsLayouter.Padding = new Extents(layouterStyle.Padding);
}
- Init();
+ ReinitializeLayout();
}
}
{
get
{
+ return (Direction)GetValue(ScrollingDirectionProperty);
+ }
+ set
+ {
+ SetValue(ScrollingDirectionProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private Direction InternalScrollingDirection
+ {
+ get
+ {
return base.ScrollingDirection;
}
set
{
base.ScrollingDirection = value;
needInitalizeLayouter = true;
- Init();
+ ReinitializeLayout();
}
}
}
/// <since_tizen> 9 </since_tizen>
public IList<object> SelectedItems
{
- get => (IList<object>)GetValue(SelectedItemsProperty);
+ get => GetValue(SelectedItemsProperty) as IList<object>;
// set => SetValue(SelectedItemsProperty, new SelectionList(this, value));
}
/// Command of selection changed.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public ICommand SelectionChangedCommand { set; get; }
+ public ICommand SelectionChangedCommand
+ {
+ get
+ {
+ return GetValue(SelectionChangedCommandProperty) as ICommand;
+ }
+ set
+ {
+ SetValue(SelectionChangedCommandProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private ICommand InternalSelectionChangedCommand { set; get; }
/// <summary>
/// Command parameter of selection changed.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public object SelectionChangedCommandParameter { set; get; }
+ public object SelectionChangedCommandParameter
+ {
+ get
+ {
+ return GetValue(SelectionChangedCommandParameterProperty);
+ }
+ set
+ {
+ SetValue(SelectionChangedCommandParameterProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private object InternalSelectionChangedCommandParameter { set; get; }
/// <summary>
/// Header item placed in top-most position.
/// <since_tizen> 9 </since_tizen>
public RecyclerViewItem Header
{
+ get
+ {
+ return GetValue(HeaderProperty) as RecyclerViewItem;
+ }
+ set
+ {
+ SetValue(HeaderProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private RecyclerViewItem InternalHeader
+ {
get => header;
set
{
InternalItemSource.HasHeader = (value != null);
}
needInitalizeLayouter = true;
- Init();
+ ReinitializeLayout();
}
}
/// <since_tizen> 9 </since_tizen>
public RecyclerViewItem Footer
{
+ get
+ {
+ return GetValue(FooterProperty) as RecyclerViewItem;
+ }
+ set
+ {
+ SetValue(FooterProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private RecyclerViewItem InternalFooter
+ {
get => footer;
set
{
InternalItemSource.HasFooter = (value != null);
}
needInitalizeLayouter = true;
- Init();
+ ReinitializeLayout();
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsGrouped
{
+ get
+ {
+ return (bool)GetValue(IsGroupedProperty);
+ }
+ set
+ {
+ SetValue(IsGroupedProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private bool InternalIsGrouped
+ {
get => isGrouped;
set
{
InternalItemSource = null;
}
if (ItemsSource != null)
+ {
InternalItemSource = ItemsSourceFactory.Create(this);
- Init();
+ }
+
+ ReinitializeLayout();
}
}
/// DataTemplate of group header.
/// </summary>
/// <remarks>Please note that, internal index will be increased by group header.
- /// GroupHeaderTemplate is essential for groupable view.</remarks>
+ /// GroupHeaderTemplate is essential for groupable view.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public DataTemplate GroupHeaderTemplate
{
get
{
+ return GetValue(GroupHeaderTemplateProperty) as DataTemplate;
+ }
+ set
+ {
+ SetValue(GroupHeaderTemplateProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private DataTemplate InternalGroupHeaderTemplate
+ {
+ get
+ {
return groupHeaderTemplate;
}
set
{
groupHeaderTemplate = value;
needInitalizeLayouter = true;
+
//Need to re-intialize Internal Item Source.
if (InternalItemSource != null)
{
InternalItemSource.Dispose();
InternalItemSource = null;
}
+
if (ItemsSource != null)
+ {
InternalItemSource = ItemsSourceFactory.Create(this);
- Init();
+ }
+
+ ReinitializeLayout();
}
}
{
get
{
+ return GetValue(GroupFooterTemplateProperty) as DataTemplate;
+ }
+ set
+ {
+ SetValue(GroupFooterTemplateProperty, value);
+ NotifyPropertyChanged();
+ }
+ }
+ private DataTemplate InternalGroupFooterTemplate
+ {
+ get
+ {
return groupFooterTemplate;
}
set
{
groupFooterTemplate = value;
needInitalizeLayouter = true;
+
//Need to re-intialize Internal Item Source.
if (InternalItemSource != null)
{
InternalItemSource.Dispose();
InternalItemSource = null;
}
+
if (ItemsSource != null)
+ {
InternalItemSource = ItemsSourceFactory.Create(this);
- Init();
+ }
+
+ ReinitializeLayout();
}
}
base.OnRelayout(size, container);
wasRelayouted = true;
- if (needInitalizeLayouter) Init();
+ if (needInitalizeLayouter)
+ {
+ ReinitializeLayout();
+ }
}
/// <inheritdoc/>
base.NotifyDataSetChanged();
}
- /// <inheritdoc/>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
- {
- View nextFocusedView = null;
-
- if (focusedView == null)
- {
- // If focusedView is null, find child which has previous data index
- if (ContentContainer.Children.Count > 0 && InternalItemSource.Count > 0)
- {
- for (int i = 0; i < ContentContainer.Children.Count; i++)
- {
- RecyclerViewItem item = Children[i] as RecyclerViewItem;
- if (item?.Index == prevFocusedDataIndex)
- {
- nextFocusedView = item;
- break;
- }
- }
- }
- }
- else
- {
- // If this is not first focus, request next focus to Layouter
- nextFocusedView = ItemsLayouter?.RequestNextFocusableView(currentFocusedView, direction, loopEnabled);
- }
-
- if (nextFocusedView != null)
- {
- // Check next focused view is inside of visible area.
- // If it is not, move scroll position to make it visible.
- Position scrollPosition = ContentContainer.CurrentPosition;
- float targetPosition = -(ScrollingDirection == Direction.Horizontal ? scrollPosition.X : scrollPosition.Y);
-
- float left = nextFocusedView.Position.X;
- float right = nextFocusedView.Position.X + nextFocusedView.Size.Width;
- float top = nextFocusedView.Position.Y;
- float bottom = nextFocusedView.Position.Y + nextFocusedView.Size.Height;
-
- float visibleRectangleLeft = -scrollPosition.X;
- float visibleRectangleRight = -scrollPosition.X + Size.Width;
- float visibleRectangleTop = -scrollPosition.Y;
- float visibleRectangleBottom = -scrollPosition.Y + Size.Height;
-
- if (ScrollingDirection == Direction.Horizontal)
- {
- if ((direction == View.FocusDirection.Left || direction == View.FocusDirection.Up) && left < visibleRectangleLeft)
- {
- targetPosition = left;
- }
- else if ((direction == View.FocusDirection.Right || direction == View.FocusDirection.Down) && right > visibleRectangleRight)
- {
- targetPosition = right - Size.Width;
- }
- }
- else
- {
- if ((direction == View.FocusDirection.Up || direction == View.FocusDirection.Left) && top < visibleRectangleTop)
- {
- targetPosition = top;
- }
- else if ((direction == View.FocusDirection.Down || direction == View.FocusDirection.Right) && bottom > visibleRectangleBottom)
- {
- targetPosition = bottom - Size.Height;
- }
- }
-
- focusedView = nextFocusedView;
- prevFocusedDataIndex = (nextFocusedView as RecyclerViewItem)?.Index ?? -1;
-
- ScrollTo(targetPosition, true);
- }
- else
- {
- // If nextView is null, it means that we should move focus to outside of Control.
- // Return FocusableView depending on direction.
- switch (direction)
- {
- case View.FocusDirection.Left:
- {
- nextFocusedView = LeftFocusableView;
- break;
- }
- case View.FocusDirection.Right:
- {
- nextFocusedView = RightFocusableView;
- break;
- }
- case View.FocusDirection.Up:
- {
- nextFocusedView = UpFocusableView;
- break;
- }
- case View.FocusDirection.Down:
- {
- nextFocusedView = DownFocusableView;
- break;
- }
- }
-
- if (nextFocusedView != null)
- {
- focusedView = null;
- }
- else
- {
- //If FocusableView doesn't exist, not move focus.
- nextFocusedView = focusedView;
- }
- }
-
- return nextFocusedView;
- }
-
/// <summary>
/// Update selected items list in multiple selection.
/// </summary>
/// <since_tizen> 9 </since_tizen>
public void UpdateSelectedItems(IList<object> newSelection)
{
- var oldSelection = new List<object>(SelectedItems);
+ if (SelectedItems != null)
+ {
+ var oldSelection = new List<object>(SelectedItems);
- suppressSelectionChangeNotification = true;
+ suppressSelectionChangeNotification = true;
- SelectedItems.Clear();
+ SelectedItems.Clear();
- if (newSelection?.Count > 0)
- {
- for (int n = 0; n < newSelection.Count; n++)
+ if (newSelection?.Count > 0)
{
- SelectedItems.Add(newSelection[n]);
+ for (int n = 0; n < newSelection.Count; n++)
+ {
+ SelectedItems.Add(newSelection[n]);
+ }
}
- }
- suppressSelectionChangeNotification = false;
+ suppressSelectionChangeNotification = false;
- SelectedItemsPropertyChanged(oldSelection, newSelection);
+ SelectedItemsPropertyChanged(oldSelection, newSelection);
+ }
}
/// <summary>
/// <since_tizen> 9 </since_tizen>
public new void ScrollTo(float position, bool animate)
{
- if (ItemsLayouter == null) throw new Exception("Item Layouter must exist.");
+ if (ItemsLayouter == null)
+ {
+ throw new Exception("Item Layouter must exist.");
+ }
+
if ((InternalItemSource == null) || needInitalizeLayouter)
{
delayedScrollTo = true;
/// <since_tizen> 9 </since_tizen>
public virtual void ScrollTo(int index, bool animate = false, ItemScrollTo align = ItemScrollTo.Nearest)
{
- if (ItemsLayouter == null) throw new Exception("Item Layouter must exist.");
+ if (ItemsLayouter == null)
+ {
+ throw new Exception("Item Layouter must exist.");
+ }
+
if ((InternalItemSource == null) || needInitalizeLayouter)
{
delayedIndexScrollTo = true;
delayedIndexScrollToParam = (index, animate, align);
return;
}
+
if (index < 0 || index >= InternalItemSource.Count)
{
throw new Exception("index is out of boundary. index should be a value between (0, " + InternalItemSource.Count.ToString() + ").");
float scrollPos, curPos, curSize, curItemSize;
(float x, float y) = ItemsLayouter.GetItemPosition(index);
(float width, float height) = ItemsLayouter.GetItemSize(index);
+
if (ScrollingDirection == Direction.Horizontal)
{
scrollPos = x;
string styleName = "Tizen.NUI.Compoenents." + (itemsLayouter is LinearLayouter? "LinearLayouter" : (itemsLayouter is GridLayouter ? "GridLayouter" : "ItemsLayouter"));
ViewStyle layouterStyle = ThemeManager.GetStyle(styleName);
if (layouterStyle != null)
+ {
itemsLayouter.Padding = new Extents(layouterStyle.Padding);
+ }
}
}
+ /// <summary>
+ /// Initialize AT-SPI object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void OnInitialize()
+ {
+ base.OnInitialize();
+ AccessibilityRole = Role.List;
+ }
/// <summary>
/// Scroll to specified item
}
// Realize and Decorate the item.
+
internal override RecyclerViewItem RealizeItem(int index)
{
RecyclerViewItem item;
var context = InternalItemSource.GetItem(index);
if (InternalItemSource.IsGroupHeader(index))
{
- DataTemplate templ = (groupHeaderTemplate as DataTemplateSelector)?.SelectDataTemplate(context, this) ?? groupHeaderTemplate;
-
- RecyclerViewItem groupHeader = PopRecycleGroupCache(templ, true);
- if (groupHeader == null)
- {
- groupHeader = (RecyclerViewItem)DataTemplateExtensions.CreateContent(groupHeaderTemplate, context, this);
-
- groupHeader.Template = templ;
- groupHeader.isGroupHeader = true;
- groupHeader.isGroupFooter = false;
- ContentContainer.Add(groupHeader);
- }
-
- if (groupHeader != null)
- {
- groupHeader.ParentItemsView = this;
- groupHeader.Index = index;
- groupHeader.ParentGroup = context;
- groupHeader.BindingContext = context;
- }
- //group selection?
- item = groupHeader;
+ item = RealizeGroupHeader(index, context);
}
else if (InternalItemSource.IsGroupFooter(index))
{
- DataTemplate templ = (groupFooterTemplate as DataTemplateSelector)?.SelectDataTemplate(context, this) ?? groupFooterTemplate;
-
- RecyclerViewItem groupFooter = PopRecycleGroupCache(templ, false);
- if (groupFooter == null)
- {
- groupFooter = (RecyclerViewItem)DataTemplateExtensions.CreateContent(groupFooterTemplate, context, this);
- groupFooter.Template = templ;
- groupFooter.isGroupHeader = false;
- groupFooter.isGroupFooter = true;
- ContentContainer.Add(groupFooter);
- }
-
- if (groupFooter != null)
- {
- groupFooter.ParentItemsView = this;
- groupFooter.Index = index;
- groupFooter.ParentGroup = context;
- groupFooter.BindingContext = context;
- }
//group selection?
- item = groupFooter;
+ item = RealizeGroupFooter(index, context);
}
else
{
item = base.RealizeItem(index);
if (item == null)
+ {
throw new Exception("Item realize failed by Null content return.");
+ }
item.ParentGroup = InternalItemSource.GetGroupParent(index);
}
}
// Unrealize and caching the item.
internal override void UnrealizeItem(RecyclerViewItem item, bool recycle = true)
{
- if (item == null) return;
+ if (item == null)
+ {
+ return;
+ }
+
if (item == Header)
{
item?.Hide();
item.Hide();
return;
}
+
if (item.isGroupHeader || item.isGroupFooter)
{
item.Index = -1;
item.ParentItemsView = null;
- item.BindingContext = null;
+ item.BindingContext = null;
item.IsPressed = false;
item.IsSelected = false;
item.IsEnabled = true;
item.UpdateState();
//item.Relayout -= OnItemRelayout;
if (!recycle || !PushRecycleGroupCache(item))
+ {
Utility.Dispose(item);
+ }
return;
}
if (item.BindingContext == null) continue;
if (newSelection.Contains(item.BindingContext))
{
- if (!item.IsSelected) item.IsSelected = true;
+ if (!item.IsSelected)
+ {
+ item.IsSelected = true;
+ }
}
else
{
- if (item.IsSelected) item.IsSelected = false;
+ if (item.IsSelected)
+ {
+ item.IsSelected = false;
+ }
}
}
SelectionPropertyChanged(this, new SelectionChangedEventArgs(oldSelection, newSelection));
groupHeaderTemplate = null;
groupFooterTemplate = null;
- if (selectedItem != null)
+ if (selectedItem != null)
{
selectedItem = null;
}
colView.OnSelectionChanged(args);
}
- private static object CoerceSelectedItems(BindableObject bindable, object value)
+ private static object CoerceSelectedItems(CollectionView colView, object value)
{
if (value == null)
{
- return new SelectionList((CollectionView)bindable);
+ return new SelectionList(colView);
}
if (value is SelectionList)
return value;
}
- return new SelectionList((CollectionView)bindable, value as IList<object>);
+ return new SelectionList(colView, value as IList<object>);
}
- private static void SelectionModePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ private static void SelectionModePropertyChanged(CollectionView colView, object oldValue, object newValue)
{
- var colView = (CollectionView)bindable;
-
var oldMode = (ItemSelectionMode)oldValue;
var newMode = (ItemSelectionMode)newValue;
SelectionPropertyChanged(colView, args);
}
- private void Init()
+ private void ReinitializeLayout()
{
- if (ItemsSource == null) return;
- if (ItemsLayouter == null) return;
- if (ItemTemplate == null) return;
-
- if (disposed) return;
- if (needInitalizeLayouter)
+ if (ItemsSource == null || ItemsLayouter == null || ItemTemplate == null)
{
- if (InternalItemSource == null) return;
+ return;
+ }
- InternalItemSource.HasHeader = (header != null);
- InternalItemSource.HasFooter = (footer != null);
+ if (disposed)
+ {
+ return;
}
- if (!wasRelayouted) return;
+ if (!wasRelayouted)
+ {
+ return;
+ }
if (needInitalizeLayouter)
{
+ if (InternalItemSource == null)
+ {
+ return;
+ }
+
+ InternalItemSource.HasHeader = (header != null);
+ InternalItemSource.HasFooter = (footer != null);
+
itemsLayouter.Clear();
ClearCache();
ItemsLayouter.Initialize(this);
needInitalizeLayouter = false;
}
+
ItemsLayouter.RequestLayout(0.0f, true);
if (delayedScrollTo)
if (ScrollingDirection == Direction.Horizontal)
{
- ContentContainer.SizeWidth = ItemsLayouter.CalculateLayoutOrientationSize();
+ ContentContainer.SizeWidth = (float)ItemsLayouter?.CalculateLayoutOrientationSize();
}
else
{
- ContentContainer.SizeHeight = ItemsLayouter.CalculateLayoutOrientationSize();
+ ContentContainer.SizeHeight = (float)ItemsLayouter?.CalculateLayoutOrientationSize();
}
}
private bool PushRecycleGroupCache(RecyclerViewItem item)
{
- if (item == null) throw new ArgumentNullException(nameof(item));
- if (RecycleCache.Count >= 20) return false;
- if (item.Template == null) return false;
+ if (item == null)
+ {
+ throw new ArgumentNullException(nameof(item));
+ }
+
+ if (item.Template == null || RecycleCache.Count >= 20)
+ {
+ return false;
+ }
+
if (item.isGroupHeader)
{
recycleGroupHeaderCache.Add(item);
{
recycleGroupFooterCache.Add(item);
}
- else return false;
+ else
+ {
+ return false;
+ }
+
item.Hide();
item.Index = -1;
+
return true;
}
for (int i = 0; i < Cache.Count; i++)
{
viewItem = Cache[i];
- if (Template == viewItem.Template) break;
+ if (Template == viewItem.Template)
+ {
+ break;
+ }
}
if (viewItem != null)
Cache.Remove(viewItem);
viewItem.Show();
}
+
return viewItem;
}
+
+ private RecyclerViewItem RealizeGroupHeader(int index, object context)
+ {
+ DataTemplate templ = (groupHeaderTemplate as DataTemplateSelector)?.SelectDataTemplate(context, this) ?? groupHeaderTemplate;
+
+ RecyclerViewItem groupHeader = PopRecycleGroupCache(templ, true);
+
+ if (groupHeader == null)
+ {
+ groupHeader = DataTemplateExtensions.CreateContent(groupHeaderTemplate, context, this) as RecyclerViewItem;
+ if (groupHeader == null)
+ {
+ return null;
+ }
+
+ groupHeader.Template = templ;
+ groupHeader.isGroupHeader = true;
+ groupHeader.isGroupFooter = false;
+ ContentContainer.Add(groupHeader);
+ }
+
+ if (groupHeader != null)
+ {
+ groupHeader.ParentItemsView = this;
+ groupHeader.Index = index;
+ groupHeader.ParentGroup = context;
+ groupHeader.BindingContext = context;
+
+ return groupHeader;
+ }
+
+ return null;
+ }
+
+ private RecyclerViewItem RealizeGroupFooter(int index, object context)
+ {
+ DataTemplate templ = (groupFooterTemplate as DataTemplateSelector)?.SelectDataTemplate(context, this) ?? groupFooterTemplate;
+
+ RecyclerViewItem groupFooter = PopRecycleGroupCache(templ, false);
+
+ if (groupFooter == null)
+ {
+ groupFooter = DataTemplateExtensions.CreateContent(groupFooterTemplate, context, this) as RecyclerViewItem;
+ if (groupFooter == null)
+ {
+ return null;
+ }
+
+ groupFooter.Template = templ;
+ groupFooter.isGroupHeader = false;
+ groupFooter.isGroupFooter = true;
+ ContentContainer.Add(groupFooter);
+ }
+
+ if (groupFooter != null)
+ {
+ groupFooter.ParentItemsView = this;
+ groupFooter.Index = index;
+ groupFooter.ParentGroup = context;
+ groupFooter.BindingContext = context;
+ return groupFooter;
+ }
+
+ return null;
+ }
+
private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
selectedItem = null;
}
-
+
if (selectedItems != null)
{
foreach (object removed in args.OldItems)