Skip to content

Commit

Permalink
Add support for NotifyCollectionChangedAction.Move to ItemsRepeater (m…
Browse files Browse the repository at this point in the history
  • Loading branch information
Kinnara committed Jul 3, 2020
1 parent 22c07f8 commit 0fa6b69
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,10 @@ public void DataSourceChanged(object source, NotifyCollectionChangedEventArgs ar
break;

case NotifyCollectionChangedAction.Move:
throw new NotImplementedException();
int size = args.OldItems != null ? args.OldItems.Count : 1;
OnItemsRemoved(args.OldStartingIndex, size);
OnItemsAdded(args.NewStartingIndex, size);
break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ internal void ClearElementOnDataSourceChange(VirtualizingLayoutContext context,
{
if (m_cachedFirstElement != null)
{
// The first element of UniformGridLayout is special since we use its size to
// determine the size of all the other elements. So if the first item has changed
// we will need to clear it and re-evalauate all the items with the new item size.
bool shouldClear = false;
switch (args.Action)
{
Expand All @@ -183,7 +186,8 @@ internal void ClearElementOnDataSourceChange(VirtualizingLayoutContext context,
break;

case NotifyCollectionChangedAction.Move:
throw new NotImplementedException();
shouldClear = args.NewStartingIndex == 0 || args.OldStartingIndex == 0;
break;
}

if (shouldClear)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ public static NotifyCollectionChangedEventArgs ConvertToDataSourceChangedEventAr
newArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, addedItems, removedItems, oldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Move:
{
List<object> movedItems = new List<object>();
for (int i = 0; i < oldItemsCount; i++)
{
movedItems.Add(null);
}
newArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, movedItems, newStartingIndex, oldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Reset:
newArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ public void Replace(int index, int oldCount, int newCount, bool reset)
}
}

public void Move(int oldIndex, int newIndex, int count, bool reset)
{
var items = Inner.GetRange(oldIndex, count);
Inner.RemoveRange(oldIndex, count);
Inner.InsertRange(newIndex, items);

if (reset)
{
OnItemsSourceChanged(CollectionChangeEventArgsConverters.CreateNotifyArgs(NotifyCollectionChangedAction.Reset, -1, -1, -1, -1));
}
else
{
OnItemsSourceChanged(CollectionChangeEventArgsConverters.CreateNotifyArgs(
NotifyCollectionChangedAction.Move,
oldStartingIndex: oldIndex,
oldItemsCount: count,
newStartingIndex: newIndex,
newItemsCount: count));
}
}

public void Reset()
{
Random rand = new Random(123);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,59 @@ public void CanReplaceSingleItem()
});
}

[TestMethod]
public void CanMoveItem()
{
CustomItemsSource dataSource = null;
RunOnUIThread.Execute(() => dataSource = new CustomItemsSource(Enumerable.Range(0, 10).ToList()));
ScrollViewer scrollViewer = null;
ItemsRepeater repeater = null;
var viewChangedEvent = new ManualResetEvent(false);

RunOnUIThread.Execute(() =>
{
repeater = SetupRepeater(dataSource, ref scrollViewer);
scrollViewer.ScrollChanged += (sender, args) =>
{
if (args.HorizontalChange != 0 || args.VerticalChange != 0)
{
viewChangedEvent.Set();
}
};
scrollViewer.ChangeView(null, 400, null, true);
});

Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged.");
IdleSynchronizer.Wait();

RunOnUIThread.Execute(() =>
{
var realized = VerifyRealizedRange(repeater, dataSource);
Verify.AreEqual(4, realized);
Log.Comment("Move before realized range.");
dataSource.Move(oldIndex: 0, newIndex: 1, count: 2, reset: false);
repeater.UpdateLayout();
realized = VerifyRealizedRange(repeater, dataSource);
Verify.AreEqual(4, realized);
Log.Comment("Move in realized range.");
dataSource.Move(oldIndex: 3, newIndex: 5, count: 2, reset: false);
repeater.UpdateLayout();
realized = VerifyRealizedRange(repeater, dataSource);
Verify.AreEqual(4, realized);
Log.Comment("Move after realized range");
dataSource.Move(oldIndex: 7, newIndex: 8, count: 2, reset: false);
repeater.UpdateLayout();
realized = VerifyRealizedRange(repeater, dataSource);
Verify.AreEqual(4, realized);
});
}

[TestMethod]
public void VerifyElement0OwnershipInUniformGridLayout()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

<Page.Resources>
<controls:RecyclePool x:Key="RecyclePool" />
<controls:RecyclingElementFactory
x:Key="elementFactory"
RecyclePool="{StaticResource RecyclePool}">
<controls:RecyclingElementFactory x:Key="elementFactory" RecyclePool="{StaticResource RecyclePool}">
<controls:RecyclingElementFactory.Templates>
<DataTemplate x:Key="Item">
<Button
Expand Down Expand Up @@ -57,6 +55,7 @@
<Button x:Name="insertButton">Insert</Button>
<Button x:Name="removeButton">Remove</Button>
<Button x:Name="replaceButton">Replace</Button>
<Button x:Name="moveButton">Move</Button>
<Button x:Name="resetButton">Reset</Button>
<Button x:Name="invalidateMeasureButton">InvalidateMeasure</Button>
<Button x:Name="invalidateArrangeButton">InvalidateArrange</Button>
Expand All @@ -70,10 +69,10 @@
<controls:ItemsRepeater x:Name="repeater">
<controls:ItemsRepeater.Layout>
<controls:UniformGridLayout
MinItemWidth="150"
MinColumnSpacing="10"
MinItemHeight="150"
MinRowSpacing="10"
MinColumnSpacing="10" />
MinItemWidth="150"
MinRowSpacing="10" />
</controls:ItemsRepeater.Layout>
<!--<controls:ItemsRepeater.Animator>
<utils:DefaultElementAnimator />
Expand All @@ -83,9 +82,9 @@
</controls:ItemsRepeaterScrollHost>

<controls:ItemsRepeater
ItemsSource="{Binding ResettingListItems, Mode=OneWay}"
x:Name="ResettingCollectionRepeater"
Grid.Row="2"
x:Name="ResettingCollectionRepeater">
ItemsSource="{Binding ResettingListItems, Mode=OneWay}">
<controls:ItemsRepeater.ItemTemplate>
<DataTemplate>
<Grid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public CollectionChangeDemo()
insertButton.Click += delegate { _dataSource.Insert(int.Parse(newStartIndex.Text), int.Parse(newCount.Text), resetMode.IsChecked ?? false); };
removeButton.Click += delegate { _dataSource.Remove(int.Parse(oldStartIndex.Text), int.Parse(oldCount.Text), resetMode.IsChecked ?? false); };
replaceButton.Click += delegate { _dataSource.Replace(int.Parse(oldStartIndex.Text), int.Parse(oldCount.Text), int.Parse(newCount.Text), resetMode.IsChecked ?? false); };
moveButton.Click += delegate { _dataSource.Move(int.Parse(oldStartIndex.Text), int.Parse(newStartIndex.Text), int.Parse(oldCount.Text), resetMode.IsChecked ?? false); };
resetButton.Click += delegate { _dataSource.Reset(); };
invalidateMeasureButton.Click += delegate { repeater.InvalidateMeasure(); };
invalidateArrangeButton.Click += delegate { repeater.InvalidateArrange(); };
Expand Down Expand Up @@ -158,6 +159,27 @@ public void Replace(int index, int oldCount, int newCount, bool reset)
}
}

public void Move(int oldIndex, int newIndex, int count, bool reset)
{
var items = Inner.GetRange(oldIndex, count);
Inner.RemoveRange(oldIndex, count);
Inner.InsertRange(newIndex, items);

if (reset)
{
OnItemsSourceChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
else
{
OnItemsSourceChanged(CollectionChangeEventArgsConverters.CreateNotifyArgs(
NotifyCollectionChangedAction.Move,
oldStartingIndex: oldIndex,
oldItemsCount: count,
newStartingIndex: newIndex,
newItemsCount: count));
}
}

public void Reset()
{
Random rand = new Random(123);
Expand Down

0 comments on commit 0fa6b69

Please sign in to comment.