using System.Linq;
using System.Collections;
using System.Collections.Generic;
+using System.Collections.Specialized;
using System.Windows.Input;
using System.ComponentModel;
using Tizen.NUI.BaseComponents;
}
set
{
+ if (itemsSource != null)
+ {
+ // Clearing old data!
+ if (itemsSource is INotifyCollectionChanged prevNotifyCollectionChanged)
+ {
+ prevNotifyCollectionChanged.CollectionChanged -= CollectionChanged;
+ }
+ itemsLayouter.Clear();
+ if (selectedItem != null) selectedItem = null;
+ if (selectedItems != null)
+ {
+ selectedItems.Clear();
+ }
+ }
itemsSource = value;
if (value == null)
//layouter.Clear()
return;
}
+ if (itemsSource is INotifyCollectionChanged newNotifyCollectionChanged)
+ {
+ newNotifyCollectionChanged.CollectionChanged += CollectionChanged;
+ }
+
if (InternalItemSource != null) InternalItemSource.Dispose();
InternalItemSource = ItemsSourceFactory.Create(this);
{
if (layouterStyle != null)
{
- itemsLayouter.Padding = new Extents(layouterStyle.Padding);
+ if (layouterStyle.Padding != null)
+ itemsLayouter.Padding = new Extents(layouterStyle.Padding);
}
}
Init();
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyDataSetChanged()
+ {
+ if (selectedItem != null)
+ {
+ selectedItem = null;
+ }
+ if (selectedItems != null)
+ {
+ selectedItems.Clear();
+ }
+
+ base.NotifyDataSetChanged();
+ }
+
+ /// <inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
{
View nextFocusedView = null;
// Realize and Decorate the item.
internal override RecyclerViewItem RealizeItem(int index)
{
+ RecyclerViewItem item;
if (index == 0 && Header != null)
{
Header.Show();
{
groupHeader = (RecyclerViewItem)DataTemplateExtensions.CreateContent(groupHeaderTemplate, context, this);
- groupHeader.ParentItemsView = this;
groupHeader.Template = templ;
groupHeader.isGroupHeader = true;
groupHeader.isGroupFooter = false;
ContentContainer.Add(groupHeader);
}
+ groupHeader.ParentItemsView = this;
groupHeader.Index = index;
groupHeader.ParentGroup = context;
groupHeader.BindingContext = context;
//group selection?
- return groupHeader;
+ item = groupHeader;
}
else if (InternalItemSource.IsGroupFooter(index))
{
{
groupFooter = (RecyclerViewItem)DataTemplateExtensions.CreateContent(groupFooterTemplate, context, this);
- groupFooter.ParentItemsView = this;
groupFooter.Template = templ;
groupFooter.isGroupHeader = false;
groupFooter.isGroupFooter = true;
ContentContainer.Add(groupFooter);
}
+ groupFooter.ParentItemsView = this;
groupFooter.Index = index;
groupFooter.ParentGroup = context;
groupFooter.BindingContext = context;
//group selection?
- return groupFooter;
+ item = groupFooter;
}
- }
-
- RecyclerViewItem item = base.RealizeItem(index);
- if (item != null)
- {
- if (isGrouped)
+ else
{
+ item = base.RealizeItem(index);
item.ParentGroup = InternalItemSource.GetGroupParent(index);
}
+ }
+ else
+ {
+ item = base.RealizeItem(index);
+ }
- switch (SelectionMode)
- {
- case ItemSelectionMode.SingleSelection:
- if (item.BindingContext != null && item.BindingContext == SelectedItem)
- {
- item.IsSelected = true;
- }
- break;
+ switch (SelectionMode)
+ {
+ case ItemSelectionMode.SingleSelection:
+ if (item.BindingContext != null && item.BindingContext == SelectedItem)
+ {
+ item.IsSelected = true;
+ }
+ break;
- case ItemSelectionMode.MultipleSelections:
- if ((item.BindingContext != null) && (SelectedItems?.Contains(item.BindingContext) ?? false))
- {
- item.IsSelected = true;
- }
- break;
- case ItemSelectionMode.None:
- item.IsSelectable = false;
- break;
- }
+ case ItemSelectionMode.MultipleSelections:
+ if ((item.BindingContext != null) && (SelectedItems?.Contains(item.BindingContext) ?? false))
+ {
+ item.IsSelected = true;
+ }
+ break;
+ case ItemSelectionMode.None:
+ item.IsSelectable = false;
+ break;
}
return item;
}
}
if (item.isGroupHeader || item.isGroupFooter)
{
+ item.Index = -1;
+ item.ParentItemsView = 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;
}
- item.IsSelected = false;
base.UnrealizeItem(item, recycle);
}
ItemsLayouter.Initialize(this);
needInitalizeLayouter = false;
}
+
base.OnScrolling(source, args);
}
if (type == DisposeTypes.Explicit)
{
disposed = true;
+
+ // From now on, no need to use this properties,
+ // so remove reference, to push it into garbage collector.
+
if (InternalItemSource != null)
{
InternalItemSource.Dispose();
}
groupHeaderTemplate = null;
groupFooterTemplate = null;
- //
+
+ if (selectedItem != null)
+ {
+ selectedItem = null;
+ }
+ if (selectedItems != null)
+ {
+ selectedItems.Clear();
+ selectedItems = null;
+ }
}
base.Dispose(type);
}
return viewItem;
}
+ private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
+ {
+ switch (args.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ // Clear removed items.
+ if (args.OldItems != null)
+ {
+ if (args.OldItems.Contains(selectedItem))
+ {
+ selectedItem = null;
+ }
+
+ if (selectedItems != null)
+ {
+ foreach (object removed in args.OldItems)
+ {
+ if (selectedItems.Contains(removed))
+ {
+ selectedItems.Remove(removed);
+ }
+ }
+ }
+ }
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ break;
+ case NotifyCollectionChangedAction.Move:
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(args));
+ }
+ }
}
}
void NotifyItemMoved(IItemSource source, int fromPosition, int toPosition);
/// <summary>
+ /// Notify the range of the observable items are moved from fromPosition to ToPosition.
+ /// </summary>
+ /// <param name="source"></param>
+ /// <param name="fromPosition"></param>
+ /// <param name="toPosition"></param>
+ /// <param name="count"></param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ void NotifyItemRangeMoved(IItemSource source, int fromPosition, int toPosition, int count);
+
+ /// <summary>
/// Notify the range of observable items from start to end are changed.
/// </summary>
/// <param name="source"></param>
notifier.NotifyItemMoved(this, localFromIndex, localToIndex);
}
+ public void NotifyItemRangeMoved(IItemSource group, int localFromIndex, int localToIndex, int count)
+ {
+ localFromIndex = GetAbsolutePosition(group, localFromIndex);
+ localToIndex = GetAbsolutePosition(group, localToIndex);
+ notifier.NotifyItemRangeMoved(this, localFromIndex, localToIndex, count);
+ }
+
public void NotifyItemRangeChanged(IItemSource group, int localStartIndex, int localEndIndex)
{
localStartIndex = GetAbsolutePosition(group, localStartIndex);
void Move(NotifyCollectionChangedEventArgs args)
{
+ var itemCount = CountItemsInGroups(args.OldStartingIndex, args.OldItems.Count);
var start = Math.Min(args.OldStartingIndex, args.NewStartingIndex);
- var end = Math.Max(args.OldStartingIndex, args.NewStartingIndex) + args.NewItems.Count;
+ var end = Math.Max(args.OldStartingIndex, args.NewStartingIndex) + itemCount;
- var itemCount = CountItemsInGroups(start, end - start);
- var absolutePosition = GetAbsolutePosition(groups[start], 0);
+ var fromPosition = GetAbsolutePosition(groups[args.OldStartingIndex], 0);
+ var toPosition = GetAbsolutePosition(groups[args.NewStartingIndex], 0);
- notifier.NotifyItemRangeChanged(this, absolutePosition, itemCount);
+ // RangeChanged give unspecified information about moves.
+ // use RangeMoved instead of rangeChanged.
+ //notifier.NotifyItemRangeChanged(this, absolutePosition, itemCount);
+ notifier.NotifyItemRangeMoved(this, fromPosition, toPosition, itemCount);
UpdateGroupTracking();
}
private float groupFooterSize;
private Extents groupFooterMargin;
private GroupInfo Visited;
+ private Timer requestLayoutTimer = null;
/// <summary>
/// Clean up ItemsLayouter.
if (i >= prevFirstVisible && i <= prevLastVisible)
{
item = GetVisibleItem(i);
- if (item) continue;
+ if (item != null && !force) continue;
+ }
+ if (item == null)
+ {
+ item = colView.RealizeItem(i);
+ if (item != null) VisibleItems.Add(item);
+ else throw new Exception("Failed to create RecycerViewItem index of ["+ i + "]");
}
- if (item == null) item = colView.RealizeItem(i);
- VisibleItems.Add(item);
//item Position without Padding and Margin.
(float x, float y) = GetItemPosition(i);
//Console.WriteLine("Realize Done");
}
+ /// <summary>
+ /// Clear the current screen and all properties.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void Clear()
+ {
+ // Clean Up
+ if (requestLayoutTimer != null)
+ {
+ requestLayoutTimer.Dispose();
+ }
+ if (groups != null)
+ {
+ /*
+ foreach (GroupInfo group in groups)
+ {
+ //group.ItemPosition?.Clear();
+ // if Disposable?
+ //group.Dispose();
+ }
+ */
+ groups.Clear();
+ }
+ if (headerMargin != null)
+ {
+ headerMargin.Dispose();
+ headerMargin = null;
+ }
+ if (footerMargin != null)
+ {
+ footerMargin.Dispose();
+ footerMargin = null;
+ }
+ if (groupHeaderMargin != null)
+ {
+ groupHeaderMargin.Dispose();
+ groupHeaderMargin = null;
+ }
+ if (groupFooterMargin != null)
+ {
+ groupFooterMargin.Dispose();
+ groupFooterMargin = null;
+ }
+
+ base.Clear();
+ }
+
/// <inheritdoc/>
public override void NotifyItemSizeChanged(RecyclerViewItem item)
{
/// <Inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemInserted(IItemSource source, int startIndex)
+ {
+ // Insert Single item.
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = 0;
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ //2. Handle Group Case.
+ if (isGrouped && gSource != null)
+ {
+ GroupInfo groupInfo = null;
+ object groupParent = gSource.GetGroupParent(startIndex);
+ int parentIndex = gSource.GetPosition(groupParent);
+ if (gSource.HasHeader) parentIndex--;
+
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ if (gSource.IsHeader(startIndex))
+ {
+ // This is childless group.
+ // create new groupInfo!
+ groupInfo = new GroupInfo()
+ {
+ GroupParent = groupParent,
+ StartIndex = startIndex,
+ Count = 1,
+ GroupSize = groupHeaderSize,
+ };
+
+ if (parentIndex >= groups.Count)
+ {
+ groupInfo.GroupPosition = ScrollContentSize;
+ groups.Add(groupInfo);
+ }
+ else
+ {
+ groupInfo.GroupPosition = groups[parentIndex].GroupPosition;
+ groups.Insert(parentIndex, groupInfo);
+ }
+
+ currentSize = groupHeaderSize;
+ }
+ else
+ {
+ // If not group parent, add item into the groupinfo.
+ if (parentIndex >= groups.Count) throw new Exception("group parent is bigger than group counts.");
+ groupInfo = groups[parentIndex];//GetGroupInfo(groupParent);
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+
+ if (gSource.IsGroupFooter(startIndex))
+ {
+ // It doesn't make sence to adding footer by notify...
+ // if GroupFooterTemplate is added,
+ // need to implement on here.
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Wrong! Grid Layouter do not support MeasureAll!
+ }
+ else
+ {
+ int pureCount = groupInfo.Count - 1 - (colView.GroupFooterTemplate == null? 0: 1);
+ if (pureCount % spanSize == 0)
+ {
+ currentSize = StepCandidate;
+ groupInfo.GroupSize += currentSize;
+ }
+
+ }
+ }
+ groupInfo.Count++;
+
+ }
+
+ if (parentIndex + 1 < groups.Count)
+ {
+ for(int i = parentIndex + 1; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition += currentSize;
+ groups[i].StartIndex++;
+ }
+ }
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Wrong! Grid Layouter do not support MeasureAll!
+ }
+ int pureCount = colView.InternalItemSource.Count - (hasHeader? 1: 0) - (hasFooter? 1: 0);
+
+ // Count comes after updated in ungrouped case!
+ if (pureCount % spanSize == 1)
+ {
+ currentSize = StepCandidate;
+ }
+ }
+
+ // 3. Update Scroll Content Size
+ ScrollContentSize += currentSize;
+
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if (item.Index >= startIndex)
+ {
+ item.Index++;
+ }
+ }
+
+ float scrollPosition = PrevScrollPosition;
+
+ /*
+ // Position Adjust
+ // Insertion above Top Visible!
+ if (startIndex <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeInserted(IItemSource source, int startIndex, int count)
+ {
+ // Insert Group
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ float currentSize = 0;
+ // Will be null if not a group.
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 2. Handle Group Case
+ // Adding ranged items should all same new groups.
+ if (isGrouped && gSource != null)
+ {
+ GroupInfo groupInfo = null;
+ object groupParent = gSource.GetGroupParent(startIndex);
+ int parentIndex = gSource.GetPosition(groupParent);
+ if (gSource.HasHeader) parentIndex--;
+ int groupStartIndex = 0;
+ if (gSource.IsGroupHeader(startIndex))
+ {
+ groupStartIndex = startIndex;
+ }
+ else
+ {
+ //exception case!
+ throw new Exception("Inserted wrong groups!");
+ }
+
+ for (int current = startIndex; current - startIndex < count; current++)
+ {
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ if (groupStartIndex == current)
+ {
+ //create new groupInfo!
+ groupInfo = new GroupInfo()
+ {
+ GroupParent = groupParent,
+ StartIndex = current,
+ Count = 1,
+ GroupSize = groupHeaderSize,
+ };
+ currentSize += groupHeaderSize;
+
+ }
+ else
+ {
+ //if not group parent, add item into the groupinfo.
+ //groupInfo = GetGroupInfo(groupStartIndex);
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ groupInfo.Count++;
+
+ if (gSource.IsGroupFooter(current))
+ {
+ groupInfo.GroupSize += groupFooterSize;
+ currentSize += groupFooterSize;
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Wrong! Grid Layouter do not support MeasureAll!
+ }
+ else
+ {
+ int index = current - groupInfo.StartIndex - 1; // groupHeader must always exist.
+ if ((index % spanSize) == 0)
+ {
+ groupInfo.GroupSize += StepCandidate;
+ currentSize += StepCandidate;
+ }
+ }
+ }
+ }
+ }
+
+ if (parentIndex >= groups.Count)
+ {
+ groupInfo.GroupPosition = ScrollContentSize;
+ groups.Add(groupInfo);
+ }
+ else
+ {
+ groupInfo.GroupPosition = groups[parentIndex].GroupPosition;
+ groups.Insert(parentIndex, groupInfo);
+ }
+
+ // Update other below group's position
+ if (parentIndex + 1 < groups.Count)
+ {
+ for(int i = parentIndex + 1; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition += currentSize;
+ groups[i].StartIndex += count;
+ }
+ }
+
+ ScrollContentSize += currentSize;
+ }
+ else
+ {
+ throw new Exception("Cannot insert ungrouped range items!");
+ }
+
+ // 3. Update Scroll Content Size
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if (item.Index >= startIndex)
+ {
+ item.Index += count;
+ }
+ }
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (startIndex + count <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRemoved(IItemSource source, int startIndex)
+ {
+ // Remove Single
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = 0;
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 2. Handle Group Case
+ if (isGrouped && gSource != null)
+ {
+ int parentIndex = 0;
+ GroupInfo groupInfo = null;
+ foreach(GroupInfo cur in groups)
+ {
+ if ((cur.StartIndex <= startIndex) && (cur.StartIndex + cur.Count - 1 >= startIndex))
+ {
+ groupInfo = cur;
+ break;
+ }
+ parentIndex++;
+ }
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ if (groupInfo.StartIndex == startIndex)
+ {
+ // This is empty group!
+ // check group is empty.
+ if (groupInfo.Count != 1)
+ {
+ throw new Exception("Cannot remove group parent");
+ }
+ currentSize = groupInfo.GroupSize;
+
+ // Remove Group
+ // groupInfo.Dispose();
+ groups.Remove(groupInfo);
+ }
+ else
+ {
+ groupInfo.Count--;
+
+ // Skip footer case as footer cannot exist alone without header.
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Wrong! Grid Layouter do not support MeasureAll!
+ }
+ else
+ {
+ int pureCount = groupInfo.Count - 1 - (colView.GroupFooterTemplate == null? 0: 1);
+ if (pureCount % spanSize == 0)
+ {
+ currentSize = StepCandidate;
+ groupInfo.GroupSize -= currentSize;
+ }
+ }
+ }
+
+ for (int i = parentIndex + 1; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition -= currentSize;
+ groups[i].StartIndex--;
+ }
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Wrong! Grid Layouter do not support MeasureAll!
+ }
+ int pureCount = colView.InternalItemSource.Count - (hasHeader? 1: 0) - (hasFooter? 1: 0);
+
+ // Count comes after updated in ungrouped case!
+ if (pureCount % spanSize == 0)
+ {
+ currentSize = StepCandidate;
+ }
+
+ }
+
+ ScrollContentSize -= currentSize;
+
+ // 3. Update Scroll Content Size
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ RecyclerViewItem targetItem = null;
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if (item.Index == startIndex)
+ {
+ targetItem = item;
+ colView.UnrealizeItem(item);
+ }
+ else if (item.Index > startIndex)
+ {
+ item.Index--;
+ }
+ }
+ VisibleItems.Remove(targetItem);
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (startIndex <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeRemoved(IItemSource source, int startIndex, int count)
+ {
+ // Remove Group
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 1. Handle Group Case
+ if (isGrouped && gSource != null)
+ {
+ int parentIndex = 0;
+ GroupInfo groupInfo = null;
+ foreach(GroupInfo cur in groups)
+ {
+ if ((cur.StartIndex == startIndex) && (cur.Count == count))
+ {
+ groupInfo = cur;
+ break;
+ }
+ parentIndex++;
+ }
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ currentSize = groupInfo.GroupSize;
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Wrong! Grid Layouter do not support MeasureAll!
+ }
+ // Remove Group
+ // groupInfo.Dispose();
+ groups.Remove(groupInfo);
+
+ for (int i = parentIndex; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition -= currentSize;
+ groups[i].StartIndex -= count;
+ }
+ }
+ else
+ {
+ // It must group case! throw exception!
+ throw new Exception("Range remove must group remove!");
+ }
+
+ ScrollContentSize -= currentSize;
+
+ // 2. Update Scroll Content Size
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 3. Update Visible Items.
+ List<RecyclerViewItem> unrealizedItems = new List<RecyclerViewItem>();
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if ((item.Index >= startIndex)
+ && (item.Index < startIndex + count))
+ {
+ unrealizedItems.Add(item);
+ colView.UnrealizeItem(item);
+ }
+ else if (item.Index >= startIndex + count)
+ {
+ item.Index -= count;
+ }
+ }
+ VisibleItems.RemoveAll(unrealizedItems.Contains);
+ unrealizedItems.Clear();
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (startIndex <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemMoved(IItemSource source, int fromPosition, int toPosition)
+ {
+ // Reorder Single
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ int diff = toPosition - fromPosition;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // Move can only happen in it's own groups.
+ // so there will be no changes in position, startIndex in ohter groups.
+ // check visible item and update indexs.
+ int startIndex = ( diff > 0 ? fromPosition: toPosition);
+ int endIndex = (diff > 0 ? toPosition: fromPosition);
+
+ if ((endIndex >= FirstVisible) && (startIndex <= LastVisible))
+ {
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if ((item.Index >= startIndex)
+ && (item.Index <= endIndex))
+ {
+ if (item.Index == fromPosition) item.Index = toPosition;
+ else
+ {
+ if (diff > 0) item.Index--;
+ else item.Index++;
+ }
+ }
+ }
+ }
+
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (((fromPosition > topInScreenIndex) && (toPosition < topInScreenIndex) ||
+ ((fromPosition < topInScreenIndex) && (toPosition > topInScreenIndex)))
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeMoved(IItemSource source, int fromPosition, int toPosition, int count)
+ {
+ // Reorder Groups
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ int diff = toPosition - fromPosition;
+
+ int startIndex = ( diff > 0 ? fromPosition: toPosition);
+ int endIndex = (diff > 0 ? toPosition + count - 1: fromPosition + count - 1);
+
+ // 2. Handle Group Case
+ if (isGrouped)
+ {
+ int fromParentIndex = 0;
+ int toParentIndex = 0;
+ bool findFrom = false;
+ bool findTo = false;
+ GroupInfo fromGroup = null;
+ GroupInfo toGroup = null;
+
+ foreach(GroupInfo cur in groups)
+ {
+ if ((cur.StartIndex == fromPosition) && (cur.Count == count))
+ {
+ fromGroup = cur;
+ findFrom = true;
+ if (findFrom && findTo) break;
+ }
+ else if (cur.StartIndex == toPosition)
+ {
+ toGroup = cur;
+ findTo = true;
+ if (findFrom && findTo) break;
+ }
+ if (!findFrom) fromParentIndex++;
+ if (!findTo) toParentIndex++;
+ }
+ if (toGroup == null || fromGroup == null) throw new Exception("Cannot find group information!");
+
+ fromGroup.StartIndex = toGroup.StartIndex;
+ fromGroup.GroupPosition = toGroup.GroupPosition;
+
+ endIndex = (diff > 0 ? toPosition + toGroup.Count - 1: fromPosition + count - 1);
+
+ groups.Remove(fromGroup);
+ groups.Insert(toParentIndex, fromGroup);
+
+ int startGroup = (diff > 0? fromParentIndex: toParentIndex);
+ int endGroup = (diff > 0? toParentIndex: fromParentIndex);
+
+ for (int i = startGroup; i <= endGroup; i++)
+ {
+ if (i == toParentIndex) continue;
+ float prevPos = groups[i].GroupPosition;
+ int prevIdx = groups[i].StartIndex;
+ groups[i].GroupPosition = groups[i].GroupPosition + (diff > 0? -1 : 1) * fromGroup.GroupSize;
+ groups[i].StartIndex = groups[i].StartIndex + (diff > 0? -1 : 1) * fromGroup.Count;
+ }
+ }
+ else
+ {
+ //It must group case! throw exception!
+ throw new Exception("Range remove must group remove!");
+ }
+
+ // Move can only happen in it's own groups.
+ // so there will be no changes in position, startIndex in ohter groups.
+ // check visible item and update indexs.
+ if ((endIndex >= FirstVisible) && (startIndex <= LastVisible))
+ {
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if ((item.Index >= startIndex)
+ && (item.Index <= endIndex))
+ {
+ if ((item.Index >= fromPosition) && (item.Index < fromPosition + count))
+ {
+ item.Index = fromPosition - item.Index + toPosition;
+ }
+ else
+ {
+ if (diff > 0) item.Index -= count;
+ else item.Index += count;
+ }
+ }
+ }
+ }
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (((fromPosition > topInScreenIndex) && (toPosition < topInScreenIndex) ||
+ ((fromPosition < topInScreenIndex) && (toPosition > topInScreenIndex)))
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
public override float CalculateLayoutOrientationSize()
{
//Console.WriteLine("[NUI] Calculate Layout ScrollContentSize {0}", ScrollContentSize);
return (sizeCandidate.Width - CandidateMargin.Start - CandidateMargin.End,
sizeCandidate.Height - CandidateMargin.Top - CandidateMargin.Bottom);
}
+ private void DelayedRequestLayout(float scrollPosition , bool force = true)
+ {
+ if (requestLayoutTimer != null)
+ {
+ requestLayoutTimer.Dispose();
+ }
+
+ requestLayoutTimer = new Timer(1);
+ requestLayoutTimer.Interval = 1;
+ requestLayoutTimer.Tick += ((object target, Timer.TickEventArgs args) =>
+ {
+ RequestLayout(scrollPosition, force);
+ return false;
+ });
+ }
private RecyclerViewItem GetVisibleItem(int index)
{
if (ItemsView != null) ItemsView.UnrealizeItem(item, false);
}
VisibleItems.Clear();
+ if (CandidateMargin != null)
+ {
+ CandidateMargin.Dispose();
+ CandidateMargin = null;
+ }
ItemsView = null;
Container = null;
}
}
/// <summary>
+ /// Notify the range of the observable items are moved from fromPosition to ToPosition.
+ /// </summary>
+ /// <param name="source"></param>
+ /// <param name="fromPosition"></param>
+ /// <param name="toPosition"></param>
+ /// <param name="count"></param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public virtual void NotifyItemRangeMoved(IItemSource source, int fromPosition, int toPosition, int count)
+ {
+ }
+
+ /// <summary>
/// Notify the range of observable items from start to end are changed.
/// </summary>
/// <param name="source">Dataset source.</param>
private float groupFooterSize;
private Extents groupFooterMargin;
private GroupInfo Visited;
+ private Timer requestLayoutTimer = null;
/// <summary>
/// Clean up ItemsLayouter.
throw new ArgumentException("LinearLayouter only can be applied CollectionView.", nameof(view));
}
// 1. Clean Up
- foreach (RecyclerViewItem item in VisibleItems)
- {
- colView.UnrealizeItem(item, false);
- }
- VisibleItems.Clear();
- ItemPosition.Clear();
- ItemSize.Clear();
- groups.Clear();
+ Clear();
FirstVisible = 0;
LastVisible = 0;
{
// Layouting is only possible after once it initialized.
if (!IsInitialized) return;
+
+ if (requestLayoutTimer != null)
+ {
+ requestLayoutTimer.Dispose();
+ requestLayoutTimer = null;
+ force = true;
+ }
+
int LastIndex = colView.InternalItemSource.Count - 1;
if (!force && PrevScrollPosition == Math.Abs(scrollPosition)) return;
}
}
VisibleItems.RemoveAll(unrealizedItems.Contains);
+ unrealizedItems.Clear();
// 3. Realize and placing visible items.
for (int i = FirstVisible; i <= LastVisible; i++)
if (i >= prevFirstVisible && i <= prevLastVisible)
{
item = GetVisibleItem(i);
- if (item) continue;
+ if (item != null && !force) continue;
}
- if (item == null) item = colView.RealizeItem(i);
- VisibleItems.Add(item);
+ if (item == null)
+ {
+ item = colView.RealizeItem(i);
+ if (item != null) VisibleItems.Add(item);
+ else throw new Exception("Failed to create RecycerViewItem index of ["+ i + "]");
+ }
// 5. Placing item.
(float posX, float posY) = GetItemPosition(i);
item.Position = new Position(posX, posY);
item.Size = new Size(Container.Size.Width - Padding.Start - Padding.End - item.Margin.Start - item.Margin.End, item.Size.Height);
}
}
+ return;
+ }
+
+ /// <summary>
+ /// Clear the current screen and all properties.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void Clear()
+ {
+ // Clean Up
+ if (requestLayoutTimer != null)
+ {
+ requestLayoutTimer.Dispose();
+ }
+ if (groups != null)
+ {
+ /*
+ foreach (GroupInfo group in groups)
+ {
+ //group.ItemPosition?.Clear();
+ // if Disposable?
+ //group.Dispose();
+ }
+ */
+ groups.Clear();
+ }
+ if (ItemPosition != null)
+ {
+ ItemPosition.Clear();
+ }
+ if (ItemSize != null)
+ {
+ ItemSize.Clear();
+ }
+ if (headerMargin != null)
+ {
+ headerMargin.Dispose();
+ headerMargin = null;
+ }
+ if (footerMargin != null)
+ {
+ footerMargin.Dispose();
+ footerMargin = null;
+ }
+ if (groupHeaderMargin != null)
+ {
+ groupHeaderMargin.Dispose();
+ groupHeaderMargin = null;
+ }
+ if (groupFooterMargin != null)
+ {
+ groupFooterMargin.Dispose();
+ groupFooterMargin = null;
+ }
+
+ base.Clear();
}
+
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override void NotifyItemSizeChanged(RecyclerViewItem item)
/// <Inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemInserted(IItemSource source, int startIndex)
+ {
+ // Insert Single item.
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 1. Handle MeasureAll
+ /*
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need To Implement
+ }
+ */
+
+ //2. Handle Group Case.
+ if (isGrouped && gSource != null)
+ {
+ GroupInfo groupInfo = null;
+ object groupParent = gSource.GetGroupParent(startIndex);
+ int parentIndex = gSource.GetPosition(groupParent);
+ if (gSource.HasHeader) parentIndex--;
+
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ if (gSource.IsHeader(startIndex))
+ {
+ // This is childless group.
+ // create new groupInfo!
+ groupInfo = new GroupInfo()
+ {
+ GroupParent = groupParent,
+ StartIndex = startIndex,
+ Count = 1,
+ GroupSize = groupHeaderSize,
+ };
+
+ if (parentIndex >= groups.Count)
+ {
+ groupInfo.GroupPosition = ScrollContentSize;
+ groups.Add(groupInfo);
+ }
+ else
+ {
+ groupInfo.GroupPosition = groups[parentIndex].GroupPosition;
+ groups.Insert(parentIndex, groupInfo);
+ }
+
+ currentSize = groupHeaderSize;
+ }
+ else
+ {
+ // If not group parent, add item into the groupinfo.
+ if (parentIndex >= groups.Count) throw new Exception("group parent is bigger than group counts.");
+ groupInfo = groups[parentIndex];//GetGroupInfo(groupParent);
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ groupInfo.Count++;
+
+ if (gSource.IsGroupFooter(startIndex))
+ {
+ // It doesn't make sence to adding footer by notify...
+ // if GroupFooterTemplate is added,
+ // need to implement on here.
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ float curPos = groupInfo.ItemPosition[startIndex - groupInfo.StartIndex];
+ groupInfo.ItemPosition.Insert(startIndex - groupInfo.StartIndex, curPos);
+ for (int i = startIndex - groupInfo.StartIndex; i < groupInfo.Count; i++)
+ {
+ groupInfo.ItemPosition[i] = curPos;
+ curPos += GetItemStepSize(parentIndex + i);
+ }
+ groupInfo.GroupSize = curPos;
+ }
+ else
+ {
+ groupInfo.GroupSize += currentSize;
+ }
+ }
+ }
+
+ if (parentIndex + 1 < groups.Count)
+ {
+ for(int i = parentIndex + 1; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition += currentSize;
+ groups[i].StartIndex++;
+ }
+ }
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Need to Implements
+ }
+
+ }
+
+ // 3. Update Scroll Content Size
+ ScrollContentSize += currentSize;
+
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if (item.Index >= startIndex)
+ {
+ item.Index++;
+ }
+ }
+
+
+ float scrollPosition = PrevScrollPosition;
+
+ /*
+ // Position Adjust
+ // Insertion above Top Visible!
+ if (startIndex <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeInserted(IItemSource source, int startIndex, int count)
+ {
+ // Insert Group
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ float currentSize = StepCandidate;
+ // Will be null if not a group.
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 1. Handle MeasureAll
+ /*
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need To Implement
+ }
+ */
+
+ // 2. Handle Group Case
+ // Adding ranged items should all same new groups.
+ if (isGrouped && gSource != null)
+ {
+ GroupInfo groupInfo = null;
+ object groupParent = gSource.GetGroupParent(startIndex);
+ int parentIndex = gSource.GetPosition(groupParent);
+ if (gSource.HasHeader) parentIndex--;
+ int groupStartIndex = 0;
+ if (gSource.IsGroupHeader(startIndex))
+ {
+ groupStartIndex = startIndex;
+ }
+ else
+ {
+ //exception case!
+ throw new Exception("Inserted wrong groups!");
+ }
+
+ for (int current = startIndex; current - startIndex < count; current++)
+ {
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ if (groupStartIndex == current)
+ {
+ //create new groupInfo!
+ groupInfo = new GroupInfo()
+ {
+ GroupParent = groupParent,
+ StartIndex = current,
+ Count = 1,
+ GroupSize = groupHeaderSize,
+ };
+
+ }
+ else
+ {
+ //if not group parent, add item into the groupinfo.
+ //groupInfo = GetGroupInfo(groupStartIndex);
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ groupInfo.Count++;
+
+ if (gSource.IsGroupFooter(current))
+ {
+ groupInfo.GroupSize += groupFooterSize;
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need To Implement
+ /*
+ float curPos = groupInfo.ItemPosition[current - groupStartIndex];
+ groupInfo.ItemPosition.Insert(current - groupStartIndex, curPos);
+ for (int i = current - groupStartIndex; i < groupInfo.Count; i++)
+ {
+ groupInfo.ItemPosition[i] = curPos;
+ curPos += GetItemSize(parentIndex + i);
+ }
+ groupInfo.GroupSize = curPos;
+ */
+ }
+ else
+ {
+ groupInfo.GroupSize += StepCandidate;
+ }
+ }
+ }
+ }
+
+ if (parentIndex >= groups.Count)
+ {
+ groupInfo.GroupPosition = ScrollContentSize;
+ groups.Add(groupInfo);
+ }
+ else
+ {
+ groupInfo.GroupPosition = groups[parentIndex].GroupPosition;
+ groups.Insert(parentIndex, groupInfo);
+ }
+
+ // Update other below group's position
+ if (parentIndex + 1 < groups.Count)
+ {
+ for(int i = parentIndex + 1; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition += groupInfo.GroupSize;
+ groups[i].StartIndex += count;
+ }
+ }
+
+ ScrollContentSize += groupInfo.GroupSize;
+ }
+ else
+ {
+ Tizen.Log.Error("NUI", "Not support insert ungrouped range items currently!");
+ }
+
+ // 3. Update Scroll Content Size
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if (item.Index >= startIndex)
+ {
+ item.Index += count;
+ }
+ }
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (startIndex + count <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRemoved(IItemSource source, int startIndex)
+ {
+ // Remove Single
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 1. Handle MeasureAll
+ /*
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need To Implement
+ }
+ */
+
+ // 2. Handle Group Case
+ if (isGrouped && gSource != null)
+ {
+ int parentIndex = 0;
+ GroupInfo groupInfo = null;
+ foreach(GroupInfo cur in groups)
+ {
+ if ((cur.StartIndex <= startIndex) && (cur.StartIndex + cur.Count - 1 >= startIndex))
+ {
+ groupInfo = cur;
+ break;
+ }
+ parentIndex++;
+ }
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ if (groupInfo.StartIndex == startIndex)
+ {
+ // This is empty group!
+ // check group is empty.
+ if (groupInfo.Count != 1)
+ {
+ throw new Exception("Cannot remove group parent");
+ }
+ currentSize = groupInfo.GroupSize;
+
+ // Remove Group
+ // groupInfo.Dispose();
+ groups.Remove(groupInfo);
+ }
+ else
+ {
+ groupInfo.Count--;
+
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need to Implement this.
+ }
+ else
+ {
+ groupInfo.GroupSize -= currentSize;
+ }
+ }
+
+ for (int i = parentIndex + 1; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition -= currentSize;
+ groups[i].StartIndex--;
+ }
+ }
+ else
+ {
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Need to Implements
+ }
+ // else Nothing to Do
+ }
+
+ ScrollContentSize -= currentSize;
+
+ // 3. Update Scroll Content Size
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ RecyclerViewItem targetItem = null;
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if (item.Index == startIndex)
+ {
+ targetItem = item;
+ colView.UnrealizeItem(item);
+ }
+ else if (item.Index > startIndex)
+ {
+ item.Index--;
+ }
+ }
+ VisibleItems.Remove(targetItem);
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (startIndex <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeRemoved(IItemSource source, int startIndex, int count)
+ {
+ // Remove Group
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 1. Handle MeasureAll
+ /*
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need To Implement
+ }
+ */
+
+ // 2. Handle Group Case
+ if (isGrouped && gSource != null)
+ {
+ int parentIndex = 0;
+ GroupInfo groupInfo = null;
+ foreach(GroupInfo cur in groups)
+ {
+ if ((cur.StartIndex == startIndex) && (cur.Count == count))
+ {
+ groupInfo = cur;
+ break;
+ }
+ parentIndex++;
+ }
+ if (groupInfo == null) throw new Exception("Cannot find group information!");
+ // Check item is group parent or not
+ // if group parent, add new gorupinfo
+ currentSize = groupInfo.GroupSize;
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ // Update ItemSize and ItemPosition
+ }
+ // Remove Group
+ // groupInfo.Dispose();
+ groups.Remove(groupInfo);
+
+ for (int i = parentIndex; i < groups.Count; i++)
+ {
+ groups[i].GroupPosition -= currentSize;
+ groups[i].StartIndex -= count;
+ }
+ }
+ else
+ {
+ //It must group case! throw exception!
+ Tizen.Log.Error("NUI", "Not support remove ungrouped range items currently!");
+ }
+
+ ScrollContentSize -= currentSize;
+
+ // 3. Update Scroll Content Size
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // 4. Update Visible Items.
+ List<RecyclerViewItem> unrealizedItems = new List<RecyclerViewItem>();
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if ((item.Index >= startIndex)
+ && (item.Index < startIndex + count))
+ {
+ unrealizedItems.Add(item);
+ colView.UnrealizeItem(item);
+ }
+ else if (item.Index >= startIndex + count)
+ {
+ item.Index -= count;
+ }
+ }
+ VisibleItems.RemoveAll(unrealizedItems.Contains);
+ unrealizedItems.Clear();
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (startIndex <= topInScreenIndex)
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemMoved(IItemSource source, int fromPosition, int toPosition)
+ {
+ // Reorder Single
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ int diff = toPosition - fromPosition;
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+ // 1. Handle MeasureAll
+ /*
+ if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
+ {
+ //Need To Implement
+ }
+ */
+
+ // Move can only happen in it's own groups.
+ // so there will be no changes in position, startIndex in ohter groups.
+ // check visible item and update indexs.
+ int startIndex = ( diff > 0 ? fromPosition: toPosition);
+ int endIndex = (diff > 0 ? toPosition: fromPosition);
+
+ if ((endIndex >= FirstVisible) && (startIndex <= LastVisible))
+ {
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if ((item.Index >= startIndex)
+ && (item.Index <= endIndex))
+ {
+ if (item.Index == fromPosition) item.Index = toPosition;
+ else
+ {
+ if (diff > 0) item.Index--;
+ else item.Index++;
+ }
+ }
+ }
+ }
+
+ if (IsHorizontal) colView.ContentContainer.SizeWidth = ScrollContentSize;
+ else colView.ContentContainer.SizeHeight = ScrollContentSize;
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (((fromPosition > topInScreenIndex) && (toPosition < topInScreenIndex) ||
+ ((fromPosition < topInScreenIndex) && (toPosition > topInScreenIndex)))
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeMoved(IItemSource source, int fromPosition, int toPosition, int count)
+ {
+ // Reorder Groups
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ // Will be null if not a group.
+ float currentSize = StepCandidate;
+ int diff = toPosition - fromPosition;
+
+ int startIndex = ( diff > 0 ? fromPosition: toPosition);
+ int endIndex = (diff > 0 ? toPosition + count - 1: fromPosition + count - 1);
+
+ // 2. Handle Group Case
+ if (isGrouped)
+ {
+ int fromParentIndex = 0;
+ int toParentIndex = 0;
+ bool findFrom = false;
+ bool findTo = false;
+ GroupInfo fromGroup = null;
+ GroupInfo toGroup = null;
+
+ foreach(GroupInfo cur in groups)
+ {
+ if ((cur.StartIndex == fromPosition) && (cur.Count == count))
+ {
+ fromGroup = cur;
+ findFrom = true;
+ if (findFrom && findTo) break;
+ }
+ else if (cur.StartIndex == toPosition)
+ {
+ toGroup = cur;
+ findTo = true;
+ if (findFrom && findTo) break;
+ }
+ if (!findFrom) fromParentIndex++;
+ if (!findTo) toParentIndex++;
+ }
+ if (toGroup == null || fromGroup == null) throw new Exception("Cannot find group information!");
+
+ fromGroup.StartIndex = toGroup.StartIndex;
+ fromGroup.GroupPosition = toGroup.GroupPosition;
+
+ endIndex = (diff > 0 ? toPosition + toGroup.Count - 1: fromPosition + count - 1);
+
+ groups.Remove(fromGroup);
+ groups.Insert(toParentIndex, fromGroup);
+
+ int startGroup = (diff > 0? fromParentIndex: toParentIndex);
+ int endGroup = (diff > 0? toParentIndex: fromParentIndex);
+
+ for (int i = startGroup; i <= endGroup; i++)
+ {
+ if (i == toParentIndex) continue;
+ float prevPos = groups[i].GroupPosition;
+ int prevIdx = groups[i].StartIndex;
+ groups[i].GroupPosition = groups[i].GroupPosition + (diff > 0? -1 : 1) * fromGroup.GroupSize;
+ groups[i].StartIndex = groups[i].StartIndex + (diff > 0? -1 : 1) * fromGroup.Count;
+ }
+ }
+ else
+ {
+ //It must group case! throw exception!
+ Tizen.Log.Error("NUI", "Not support move ungrouped range items currently!");
+ }
+
+ // Move can only happen in it's own groups.
+ // so there will be no changes in position, startIndex in ohter groups.
+ // check visible item and update indexs.
+ if ((endIndex >= FirstVisible) && (startIndex <= LastVisible))
+ {
+ foreach (RecyclerViewItem item in VisibleItems)
+ {
+ if ((item.Index >= startIndex)
+ && (item.Index <= endIndex))
+ {
+ if ((item.Index >= fromPosition) && (item.Index < fromPosition + count))
+ {
+ item.Index = fromPosition - item.Index + toPosition;
+ }
+ else
+ {
+ if (diff > 0) item.Index -= count;
+ else item.Index += count;
+ }
+ }
+ }
+ }
+
+ // Position Adjust
+ float scrollPosition = PrevScrollPosition;
+ /*
+ // Insertion above Top Visible!
+ if (((fromPosition > topInScreenIndex) && (toPosition < topInScreenIndex) ||
+ ((fromPosition < topInScreenIndex) && (toPosition > topInScreenIndex)))
+ {
+ scrollPosition = GetItemPosition(topInScreenIndex);
+ scrollPosition -= offset;
+
+ colView.ScrollTo(scrollPosition);
+ }
+ */
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(scrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override void NotifyItemRangeChanged(IItemSource source, int startRange, int endRange)
+ {
+ // Reorder Group
+ if (source == null) throw new ArgumentNullException(nameof(source));
+ IGroupableItemSource gSource = source as IGroupableItemSource;
+ if (gSource == null)throw new Exception("Source is not group!");
+
+ // Get the first Visible Position to adjust.
+ /*
+ int topInScreenIndex = 0;
+ float offset = 0F;
+ (topInScreenIndex, offset) = FindTopItemInScreen();
+ */
+
+
+ // Unrealize, initialized all items in the Range
+ // and receate all.
+
+ // Update Viewport in delay.
+ // FIMXE: original we only need to process RequestLayout once before layout calculation in main loop.
+ // but currently we do not have any accessor to pre-calculation so instead of this,
+ // using Timer temporarily.
+ DelayedRequestLayout(PrevScrollPosition);
+ }
+
+ /// <Inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
public override float CalculateLayoutOrientationSize()
{
//Console.WriteLine("[NUI] Calculate Layout ScrollContentSize {0}", ScrollContentSize);
}
}
+ private void DelayedRequestLayout(float scrollPosition , bool force = true)
+ {
+ if (requestLayoutTimer != null)
+ {
+ requestLayoutTimer.Dispose();
+ }
+
+ requestLayoutTimer = new Timer(1);
+ requestLayoutTimer.Interval = 1;
+ requestLayoutTimer.Tick += ((object target, Timer.TickEventArgs args) =>
+ {
+ RequestLayout(scrollPosition, force);
+ return false;
+ });
+ }
+
+ /*
+ private (int, float) FindTopItemInScreen()
+ {
+ int index = -1;
+ float offset = 0.0F, Pos, Size;
+
+ foreach(RecyclerViewItem item in VisibleItems)
+ {
+ Pos = IsHorizontal ? item.PositionX : item.PositionY;
+ Size = IsHorizontal ? item.SizeWidth : item.SizeHeight;
+ if (PrevScrollPosition >= Pos && PrevScrollPosition < Pos + Size)
+ {
+ index = item.Index;
+ offset = Pos - PrevScrollPosition;
+ break;
+ }
+ }
+
+ return (index, offset);
+ }
+ */
+
private float GetItemStepSize(int index)
{
if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll)
/// Notify Dataset is Changed.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyDataSetChanged()
+ public virtual void NotifyDataSetChanged()
{
//Need to update view.
if (InternalItemsLayouter != null)
/// <param name="source">Dataset source.</param>
/// <param name="startIndex">Changed item index.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemChanged(IItemSource source, int startIndex)
+ public virtual void NotifyItemChanged(IItemSource source, int startIndex)
{
if (InternalItemsLayouter != null)
{
}
/// <summary>
- /// Notify observable item is inserted in dataset.
+ /// Notify range of observable items from start to end are changed.
/// </summary>
/// <param name="source">Dataset source.</param>
- /// <param name="startIndex">Inserted item index.</param>
+ /// <param name="startRange">Start index of changed items range.</param>
+ /// <param name="endRange">End index of changed items range.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemInserted(IItemSource source, int startIndex)
+ public virtual void NotifyItemRangeChanged(IItemSource source, int startRange, int endRange)
{
if (InternalItemsLayouter != null)
{
- InternalItemsLayouter.NotifyItemInserted(source, startIndex);
+ InternalItemsLayouter.NotifyItemRangeChanged(source, startRange, endRange);
}
}
/// <summary>
- /// Notify observable item is moved from fromPosition to ToPosition.
+ /// Notify observable item is inserted in dataset.
/// </summary>
/// <param name="source">Dataset source.</param>
- /// <param name="fromPosition">Previous item position.</param>
- /// <param name="toPosition">Moved item position.</param>
+ /// <param name="startIndex">Inserted item index.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemMoved(IItemSource source, int fromPosition, int toPosition)
+ public virtual void NotifyItemInserted(IItemSource source, int startIndex)
{
if (InternalItemsLayouter != null)
{
- InternalItemsLayouter.NotifyItemMoved(source, fromPosition, toPosition);
+ InternalItemsLayouter.NotifyItemInserted(source, startIndex);
}
}
/// <summary>
- /// Notify range of observable items from start to end are changed.
+ /// Notify count range of observable count items are inserted in startIndex.
/// </summary>
/// <param name="source">Dataset source.</param>
- /// <param name="start">Start index of changed items range.</param>
- /// <param name="end">End index of changed items range.</param>
+ /// <param name="startIndex">Start index of inserted items range.</param>
+ /// <param name="count">The number of inserted items.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemRangeChanged(IItemSource source, int start, int end)
+ public virtual void NotifyItemRangeInserted(IItemSource source, int startIndex, int count)
{
if (InternalItemsLayouter != null)
{
- InternalItemsLayouter.NotifyItemRangeChanged(source, start, end);
+ InternalItemsLayouter.NotifyItemRangeInserted(source, startIndex, count);
}
}
/// <summary>
- /// Notify count range of observable count items are inserted in startIndex.
+ /// Notify observable item is moved from fromPosition to ToPosition.
/// </summary>
/// <param name="source">Dataset source.</param>
- /// <param name="startIndex">Start index of inserted items range.</param>
- /// <param name="count">The number of inserted items.</param>
+ /// <param name="fromPosition">Previous item position.</param>
+ /// <param name="toPosition">Moved item position.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemRangeInserted(IItemSource source, int startIndex, int count)
+ public virtual void NotifyItemMoved(IItemSource source, int fromPosition, int toPosition)
{
if (InternalItemsLayouter != null)
{
- InternalItemsLayouter.NotifyItemRangeInserted(source, startIndex, count);
+ InternalItemsLayouter.NotifyItemMoved(source, fromPosition, toPosition);
}
}
/// <summary>
- /// Notify the count range of observable items from the startIndex are removed.
+ /// Notify the observable item is moved from fromPosition to ToPosition.
/// </summary>
- /// <param name="source">Dataset source.</param>
- /// <param name="startIndex">Start index of removed items range.</param>
- /// <param name="count">The number of removed items</param>
+ /// <param name="source"></param>
+ /// <param name="fromPosition"></param>
+ /// <param name="toPosition"></param>
+ /// <param name="count"></param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemRangeRemoved(IItemSource source, int startIndex, int count)
+ public virtual void NotifyItemRangeMoved(IItemSource source, int fromPosition, int toPosition, int count)
{
if (InternalItemsLayouter != null)
{
- InternalItemsLayouter.NotifyItemRangeRemoved(source, startIndex, count);
+ InternalItemsLayouter.NotifyItemRangeMoved(source, fromPosition, toPosition, count);
}
}
/// <param name="source">Dataset source.</param>
/// <param name="startIndex">Index of removed item.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public void NotifyItemRemoved(IItemSource source, int startIndex)
+ public virtual void NotifyItemRemoved(IItemSource source, int startIndex)
{
if (InternalItemsLayouter != null)
{
}
/// <summary>
+ /// Notify the count range of observable items from the startIndex are removed.
+ /// </summary>
+ /// <param name="source">Dataset source.</param>
+ /// <param name="startIndex">Start index of removed items range.</param>
+ /// <param name="count">The number of removed items</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public virtual void NotifyItemRangeRemoved(IItemSource source, int startIndex, int count)
+ {
+ if (InternalItemsLayouter != null)
+ {
+ InternalItemsLayouter.NotifyItemRangeRemoved(source, startIndex, count);
+ }
+ }
+
+ /// <summary>
/// Realize indexed item.
/// </summary>
/// <param name="index"> Index position of realizing item </param>
{
item.Index = -1;
item.ParentItemsView = null;
- // Remove BindingContext null set for performance improving.
- //item.BindingContext = null;
+ item.BindingContext = null;
item.IsPressed = false;
item.IsSelected = false;
item.IsEnabled = true;
- // Remove Update Style on default for performance improving.
- //item.UpdateState();
+ item.UpdateState();
item.Relayout -= OnItemRelayout;
if (!recycle || !PushRecycleCache(item))
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using Tizen.NUI.BaseComponents;
using Tizen.NUI.Components;
using Tizen.NUI.Binding;
+using System;
namespace Tizen.NUI.Samples
{
{
CollectionView colView;
int itemCount = 500;
- int selectedCount;
ItemSelectionMode selMode;
+ ObservableCollection<Gallery> gallerySource;
+ Gallery insertMenu = new Gallery(999, "Insert item to 3rd");
+ Gallery deleteMenu = new Gallery(999, "Delete item at 3rd");
+ Gallery moveMenu = new Gallery(999, "Move last item to 3rd");
public void Activate()
{
Window window = NUIApplication.GetDefaultWindow();
- var myViewModelSource = new GalleryViewModel(itemCount);
+ var myViewModelSource = gallerySource = new GalleryViewModel(itemCount);
+ // Add test menu options.
+ gallerySource.Insert(0, moveMenu);
+ gallerySource.Insert(0, deleteMenu);
+ gallerySource.Insert(0, insertMenu);
+
selMode = ItemSelectionMode.MultipleSelections;
DefaultTitleItem myTitle = new DefaultTitleItem();
- myTitle.Text = "Grid Sample Count["+itemCount+"] Selected["+selectedCount+"]";
+ myTitle.Text = "Grid Sample Count["+itemCount+"]";
//Set Width Specification as MatchParent to fit the Item width with parent View.
myTitle.WidthSpecification = LayoutParamPolicies.MatchParent;
{
galItem.Selected = false;
Tizen.Log.Debug("Unselected: {0}", galItem.ViewLabel);
- selectedCount--;
}
}
else continue;
{
galItem.Selected = true;
Tizen.Log.Debug("Selected: {0}", galItem.ViewLabel);
- selectedCount++;
+
+ // Check test menu options.
+ if (galItem == insertMenu)
+ {
+ // Insert new item to index 3.
+ Random rand = new Random();
+ int idx = rand.Next(1000);
+ gallerySource.Insert(3, new Gallery(idx, "Inserted Item"));
+ }
+ else if (galItem == deleteMenu)
+ {
+ // Remove item in index 3.
+ gallerySource.RemoveAt(3);
+ }
+ else if (galItem == moveMenu)
+ {
+ // Move last indexed item to index 3.
+ gallerySource.Move(gallerySource.Count - 1, 3);
+ }
}
+
}
else continue;
}
if (colView.Header != null && colView.Header is DefaultTitleItem)
{
DefaultTitleItem title = (DefaultTitleItem)colView.Header;
- title.Text = "Grid Sample Count["+itemCount+"] Selected["+selectedCount+"]";
+ title.Text = "Grid Sample Count["+gallerySource.Count+"] Selected["+newSel.Count+"]";
}
}
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using Tizen.NUI.BaseComponents;
using Tizen.NUI.Components;
using Tizen.NUI.Binding;
int itemCount = 500;
string selectedItem;
ItemSelectionMode selMode;
+ ObservableCollection<Gallery> gallerySource;
+ Gallery insertMenu = new Gallery(999, "Insert item to 3rd");
+ Gallery deleteMenu = new Gallery(999, "Delete item at 3rd");
+ Gallery moveMenu = new Gallery(999, "Move last item to 3rd");
+
public void Activate()
{
Window window = NUIApplication.GetDefaultWindow();
- var myViewModelSource = new GalleryViewModel(itemCount);
+ var myViewModelSource = gallerySource = new GalleryViewModel(itemCount);
+ // Add test menu options.
+ gallerySource.Insert(0, moveMenu);
+ gallerySource.Insert(0, deleteMenu);
+ gallerySource.Insert(0, insertMenu);
+
selMode = ItemSelectionMode.SingleSelection;
DefaultTitleItem myTitle = new DefaultTitleItem();
myTitle.Text = "Linear Sample Count["+itemCount+"]";
{
if (item == null) break;
Gallery selItem = (Gallery)item;
- selItem.Selected = true;
+ //selItem.Selected = true;
selectedItem = selItem.Name;
+
+ // Check test menu options.
+ if (selItem == insertMenu)
+ {
+ // Insert new item to index 3.
+ Random rand = new Random();
+ int idx = rand.Next(1000);
+ gallerySource.Insert(3, new Gallery(idx, "Inserted Item"));
+ }
+ else if (selItem == deleteMenu)
+ {
+ // Remove item in index 3.
+ gallerySource.RemoveAt(3);
+ }
+ else if (selItem == moveMenu)
+ {
+ // Move last indexed item to index 3.
+ gallerySource.Move(gallerySource.Count - 1, 3);
+ }
//Tizen.Log.Debug("NUI", "LSH :: Selected: {0}", selItem.ViewLabel);
}
if (colView.Header != null && colView.Header is DefaultTitleItem)
{
DefaultTitleItem title = (DefaultTitleItem)colView.Header;
- title.Text = "Linear Sample Count[" + itemCount + (selectedItem != null ? "] Selected [" + selectedItem + "]" : "]");
+ title.Text = "Linear Sample Count[" + gallerySource.Count + (selectedItem != null ? "] Selected [" + selectedItem + "]" : "]");
}
}
+
public void Deactivate()
{
if (colView != null)
using Tizen.NUI.Binding;
-
class Gallery : INotifyPropertyChanged
{
string sourceDir = Tizen.NUI.Samples.CommonResource.GetDaliResourcePath()+"ItemViewDemo/gallery/gallery-medium-";
private int index;
private string name;
private DateTime date;
+ private bool selected;
public Album(int albumIndex, string albumName, DateTime albumDate)
{
return date.ToLongDateString();
}
}
+ public bool Selected {
+ get
+ {
+ return selected;
+ }
+ set
+ {
+ selected = value;
+ }
+ }
}
class GalleryViewModel : ObservableCollection<Gallery>
("Graduation", new DateTime(2017, 6, 30)),
};
-
public AlbumViewModel()
{
CreateData(this);
public class CollectionViewGridGroupSample : IExample
{
CollectionView colView;
- int selectedCount;
ItemSelectionMode selMode;
- ObservableCollection<Album> groupSource;
+ ObservableCollection<Album> albumSource;
+ Album insertDeleteGroup = new Album(999, "Insert / Delete Groups", new DateTime(1999, 12, 31));
+ Gallery insertMenu = new Gallery(999, "Insert item to first of 3rd Group");
+ Gallery deleteMenu = new Gallery(999, "Delete first item in 3rd Group");
+ Album moveGroup = new Album(999, "move Groups", new DateTime(1999, 12, 31));
+ Gallery moveMenu = new Gallery(999, "Move last item to first in 3rd group");
public void Activate()
{
Window window = NUIApplication.GetDefaultWindow();
- groupSource = new AlbumViewModel();
+ albumSource = new AlbumViewModel();
+ // Add test menu options.
+ moveGroup.Add(moveMenu);
+ albumSource.Insert(0, moveGroup);
+ insertDeleteGroup.Add(insertMenu);
+ insertDeleteGroup.Add(deleteMenu);
+ albumSource.Insert(0, insertDeleteGroup);
+
selMode = ItemSelectionMode.MultipleSelections;
DefaultTitleItem myTitle = new DefaultTitleItem();
- myTitle.Text = "Grid Sample Count["+ groupSource.Count+"] Selected["+selectedCount+"]";
+ myTitle.Text = "Grid Sample Count["+ albumSource.Count+"]";
//Set Width Specification as MatchParent to fit the Item width with parent View.
myTitle.WidthSpecification = LayoutParamPolicies.MatchParent;
colView = new CollectionView()
{
- ItemsSource = groupSource,
+ ItemsSource = albumSource,
ItemsLayouter = new GridLayouter(),
ItemTemplate = new DataTemplate(() =>
{
if (!(newSel.Contains(item)))
{
galItem.Selected = false;
- Tizen.Log.Debug("Unselected: {0}", galItem.ViewLabel);
- selectedCount--;
+ // Tizen.Log.Debug("Unselected: {0}", galItem.ViewLabel);
+ }
+ }
+ else if (item is Album selAlbum)
+ {
+ if (!(newSel.Contains(selAlbum)))
+ {
+ selAlbum.Selected = false;
+ // Tizen.Log.Debug("Unselected Group: {0}", selAlbum.Title);
+ if (selAlbum == insertDeleteGroup)
+ {
+ albumSource.RemoveAt(2);
+ }
}
}
- else continue;
}
foreach (object item in newSel)
{
if (!(oldSel.Contains(item)))
{
galItem.Selected = true;
- Tizen.Log.Debug("Selected: {0}", galItem.ViewLabel);
- selectedCount++;
+ // Tizen.Log.Debug("Selected: {0}", galItem.ViewLabel);
+
+ if (galItem == insertMenu)
+ {
+ // Insert new item to index 3.
+ Random rand = new Random();
+ int idx = rand.Next(1000);
+ albumSource[2].Insert(3, new Gallery(idx, "Inserted Item"));
+ }
+ else if (galItem == deleteMenu)
+ {
+ // Remove item in index 3.
+ albumSource[2].RemoveAt(0);
+ }
+ else if (galItem == moveMenu)
+ {
+ // Move last indexed item to index 3.
+ albumSource[2].Move(albumSource[2].Count - 1, 0);
+ }
+ }
+ }
+ else if (item is Album selAlbum)
+ {
+ if (!(oldSel.Contains(selAlbum)))
+ {
+ selAlbum.Selected = true;
+ // Tizen.Log.Debug("Selected Group: {0}", selAlbum.Title);
+ if (selAlbum == insertDeleteGroup)
+ {
+ Random rand = new Random();
+ int groupIdx = rand.Next(1000);
+ Album insertAlbum = new Album(groupIdx, "Inserted group", new DateTime(1999, 12, 31));
+ int idx = rand.Next(1000);
+ insertAlbum.Add(new Gallery(idx, "Inserted Item 1"));
+ idx = rand.Next(1000);
+ insertAlbum.Add(new Gallery(idx, "Inserted Item 2"));
+ idx = rand.Next(1000);
+ insertAlbum.Add(new Gallery(idx, "Inserted Item 3"));
+ albumSource.Insert(2, insertAlbum);
+ }
+ else if (selAlbum == moveGroup)
+ {
+ albumSource.Move(albumSource.Count - 1, 2);
+
+ }
}
}
- else continue;
}
if (colView.Header != null && colView.Header is DefaultTitleItem)
{
DefaultTitleItem title = (DefaultTitleItem)colView.Header;
- title.Text = "Grid Sample Count["+ groupSource.Count + "] Selected["+selectedCount+"]";
+ title.Text = "Grid Sample Count["+ albumSource.Count + "] Selected["+newSel.Count+"]";
}
}
CollectionView colView;
string selectedItem;
ItemSelectionMode selMode;
- ObservableCollection<Album> groupSource;
+ ObservableCollection<Album> albumSource;
+ Album insertDeleteGroup = new Album(999, "Insert / Delete Groups", new DateTime(1999, 12, 31));
+ Gallery insertMenu = new Gallery(999, "Insert item to first of 3rd Group");
+ Gallery deleteMenu = new Gallery(999, "Delete first item in 3rd Group");
+ Album moveGroup = new Album(999, "move Groups", new DateTime(1999, 12, 31));
+ Gallery moveMenu = new Gallery(999, "Move last item to first in 3rd group");
public void Activate()
{
Window window = NUIApplication.GetDefaultWindow();
- groupSource = new AlbumViewModel();
+ albumSource = new AlbumViewModel();
+ // Add test menu options.
+ moveGroup.Add(moveMenu);
+ albumSource.Insert(0, moveGroup);
+ insertDeleteGroup.Add(insertMenu);
+ insertDeleteGroup.Add(deleteMenu);
+ albumSource.Insert(0, insertDeleteGroup);
+
selMode = ItemSelectionMode.SingleSelection;
DefaultTitleItem myTitle = new DefaultTitleItem();
//To Bind the Count property changes, need to create custom property for count.
- myTitle.Text = "Linear Sample Group["+ groupSource.Count+"]";
+ myTitle.Text = "Linear Sample Group["+ albumSource.Count+"]";
//Set Width Specification as MatchParent to fit the Item width with parent View.
myTitle.WidthSpecification = LayoutParamPolicies.MatchParent;
colView = new CollectionView()
{
- ItemsSource = groupSource,
+ ItemsSource = albumSource,
ItemsLayouter = new LinearLayouter(),
ItemTemplate = new DataTemplate(() =>
{
- var rand = new Random();
- RecyclerViewItem item = new RecyclerViewItem();
- item.WidthSpecification = LayoutParamPolicies.MatchParent;
- item.HeightSpecification = 100;
- item.BackgroundColor = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), 1);
- /*
DefaultLinearItem item = new DefaultLinearItem();
//Set Width Specification as MatchParent to fit the Item width with parent View.
item.WidthSpecification = LayoutParamPolicies.MatchParent;
//item.Extra.SetBinding(RadioButton.IsSelectedProperty, "Selected");
item.Extra.WidthSpecification = 80;
item.Extra.HeightSpecification = 80;
- */
+
return item;
}),
GroupHeaderTemplate = new DataTemplate(() =>
{
- var rand = new Random();
- RecyclerViewItem item = new RecyclerViewItem();
- item.WidthSpecification = LayoutParamPolicies.MatchParent;
- item.HeightSpecification = 50;
- item.BackgroundColor = new Color(0, 0, 0, 1);
- /*
DefaultTitleItem group = new DefaultTitleItem();
//Set Width Specification as MatchParent to fit the Item width with parent View.
group.WidthSpecification = LayoutParamPolicies.MatchParent;
group.Label.SetBinding(TextLabel.TextProperty, "Date");
group.Label.HorizontalAlignment = HorizontalAlignment.Begin;
- */
- return item;
+
+ return group;
}),
Header = myTitle,
IsGrouped = true,
foreach (object item in ev.PreviousSelection)
{
if (item == null) break;
- Gallery unselItem = (Gallery)item;
-
- unselItem.Selected = false;
- selectedItem = null;
- //Tizen.Log.Debug("NUI", "LSH :: Unselected: {0}", unselItem.ViewLabel);
+ if (item is Gallery unselItem)
+ {
+ unselItem.Selected = false;
+ selectedItem = null;
+ //Tizen.Log.Debug("NUI", "LSH :: Unselected: {0}", unselItem.ViewLabel);
+ }
+ else if (item is Album selAlbum)
+ {
+ selectedItem = selAlbum.Title;
+ selAlbum.Selected = false;
+ if (selAlbum == insertDeleteGroup)
+ {
+ albumSource.RemoveAt(2);
+ }
+ }
+
}
foreach (object item in ev.CurrentSelection)
{
if (item == null) break;
- Gallery selItem = (Gallery)item;
- selItem.Selected = true;
- selectedItem = selItem.Name;
- //Tizen.Log.Debug("NUI", "LSH :: Selected: {0}", selItem.ViewLabel);
+ if (item is Gallery selItem)
+ {
+ selItem.Selected = true;
+ selectedItem = selItem.Name;
+ //Tizen.Log.Debug("NUI", "LSH :: Selected: {0}", selItem.ViewLabel);
+
+ // Check test menu options.
+ if (selItem == insertMenu)
+ {
+ // Insert new item to index 3.
+ Random rand = new Random();
+ int idx = rand.Next(1000);
+ albumSource[2].Insert(0, new Gallery(idx, "Inserted Item"));
+ }
+ else if (selItem == deleteMenu)
+ {
+ // Remove item in index 3.
+ albumSource[2].RemoveAt(0);
+ }
+ else if (selItem == moveMenu)
+ {
+ // Move last indexed item to index 3.
+ albumSource[2].Move(albumSource[2].Count - 1, 0);
+ }
+ }
+ else if (item is Album selAlbum)
+ {
+ selectedItem = selAlbum.Title;
+ selAlbum.Selected = true;
+ if (selAlbum == insertDeleteGroup)
+ {
+ Random rand = new Random();
+ int groupIdx = rand.Next(1000);
+ Album insertAlbum = new Album(groupIdx, "Inserted group", new DateTime(1999, 12, 31));
+ int idx = rand.Next(1000);
+ insertAlbum.Add(new Gallery(idx, "Inserted Item 1"));
+ idx = rand.Next(1000);
+ insertAlbum.Add(new Gallery(idx, "Inserted Item 2"));
+ idx = rand.Next(1000);
+ insertAlbum.Add(new Gallery(idx, "Inserted Item 3"));
+ albumSource.Insert(2, insertAlbum);
+ }
+ else if (selAlbum == moveGroup)
+ {
+ albumSource.Move(albumSource.Count - 1, 2);
+
+ }
+ }
}
if (colView.Header != null && colView.Header is DefaultTitleItem)
{
DefaultTitleItem title = (DefaultTitleItem)colView.Header;
- title.Text = "Linear Sample Count[" + groupSource + (selectedItem != null ? "] Selected [" + selectedItem + "]" : "]");
+ title.Text = "Linear Sample Count[" + albumSource.Count + (selectedItem != null ? "] Selected [" + selectedItem + "]" : "]");
}
}
+
public void Deactivate()
{
if (colView != null)