From ebdca5d8083d433c8b594dd16eb8715033bf7eb2 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Mon, 28 Sep 2020 14:54:06 +0200 Subject: [PATCH] fix(ListViewBase): Item container indices not updated on insert/remove --- .../Controls/ListViewBase/ListViewBase.cs | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.cs index 873b6b0ebdd1..5a799e3eaa6b 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.cs @@ -49,6 +49,8 @@ public partial class ListViewBase : Selector /// private bool _isIncrementalLoadingInFlight; + private readonly Dictionary _containersForIndexRepair = new Dictionary(); + protected internal ListViewBase() { Initialize(); @@ -58,7 +60,7 @@ protected internal ListViewBase() SelectedItems = selectedItems; } - public event TypedEventHandler ContainerContentChanging; + public event TypedEventHandler ContainerContentChanging; protected override Size ArrangeOverride(Size finalSize) { @@ -173,7 +175,8 @@ internal override void ChangeSelectedItem(object item, bool oldIsSelected, bool { SelectedIndex = -1; } - } else + } + else { SelectedIndex = index; } @@ -461,7 +464,11 @@ internal override void OnItemsSourceSingleCollectionChanged(object sender, Notif { this.Log().Debug($"Inserting {args.NewItems.Count} items starting at {args.NewStartingIndex}"); } + + SaveContainersForIndexRepair(args.NewStartingIndex, args.NewItems.Count); AddItems(args.NewStartingIndex, args.NewItems.Count, section); + RepairIndices(); + break; case NotifyCollectionChangedAction.Remove: if (AreEmptyGroupsHidden && (sender as IEnumerable).None()) @@ -475,14 +482,20 @@ internal override void OnItemsSourceSingleCollectionChanged(object sender, Notif { this.Log().Debug($"Deleting {args.OldItems.Count} items starting at {args.OldStartingIndex}"); } + + SaveContainersForIndexRepair(args.OldStartingIndex, -args.OldItems.Count); RemoveItems(args.OldStartingIndex, args.OldItems.Count, section); + RepairIndices(); + break; case NotifyCollectionChangedAction.Replace: if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { this.Log().Debug($"Replacing {args.NewItems.Count} items starting at {args.NewStartingIndex}"); } + ReplaceItems(args.NewStartingIndex, args.NewItems.Count, section); + break; case NotifyCollectionChangedAction.Move: // TODO PBI #19974: Fully implement NotifyCollectionChangedActions and map them to the appropriate calls @@ -505,6 +518,28 @@ void completeRefresh() } } + private void SaveContainersForIndexRepair(int startingIndex, int indexChange) + { + _containersForIndexRepair.Clear(); + foreach (var container in MaterializedContainers) + { + var currentIndex = (int)container.GetValue(ItemsControl.IndexForItemContainerProperty); + if (currentIndex >= startingIndex) + { + _containersForIndexRepair.Add(container, currentIndex + indexChange); + } + } + } + + private void RepairIndices() + { + foreach(var containerPair in _containersForIndexRepair) + { + containerPair.Key.SetValue(ItemsControl.IndexForItemContainerProperty, containerPair.Value); + } + _containersForIndexRepair.Clear(); + } + internal override void OnItemsSourceGroupsChanged(object sender, NotifyCollectionChangedEventArgs args) { if (RefreshOnCollectionChanged) @@ -596,6 +631,9 @@ internal override void OnGroupPropertyChanged(ICollectionViewGroup group, int gr protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { + // Index will be repaired by virtue of ItemsControl. + _containersForIndexRepair.Remove(element); + base.PrepareContainerForItemOverride(element, item); if (element is SelectorItem selectorItem) @@ -607,7 +645,7 @@ protected override void PrepareContainerForItemOverride(DependencyObject element internal override void ContainerPreparedForItem(object item, SelectorItem itemContainer, int itemIndex) { base.ContainerPreparedForItem(item, itemContainer, itemIndex); - + ContainerContentChanging?.Invoke(this, new ContainerContentChangingEventArgs(item, itemContainer, itemIndex)); }