diff --git a/VirtualListView/Controls/VirtualListView.cs b/VirtualListView/Controls/VirtualListView.cs index cb890bf..3052297 100644 --- a/VirtualListView/Controls/VirtualListView.cs +++ b/VirtualListView/Controls/VirtualListView.cs @@ -247,20 +247,20 @@ public ICommand? ScrolledCommand } public static readonly BindableProperty SelectedItemsProperty = - BindableProperty.Create(nameof(SelectedItems), typeof(IList), typeof(VirtualListView), Array.Empty(), + BindableProperty.Create(nameof(SelectedItems), typeof(ISet), typeof(VirtualListView), new HashSet(), propertyChanged: (bindableObj, oldValue, newValue) => { if (bindableObj is VirtualListView vlv - && oldValue is IList oldSelection - && newValue is IList newSelection) + && oldValue is ISet oldSelection + && newValue is ISet newSelection) { vlv.RaiseSelectedItemsChanged(oldSelection.ToArray(), newSelection.ToArray()); } }); - public IList? SelectedItems + public ISet? SelectedItems { - get => (IList)GetValue(SelectedItemsProperty); - set => SetValue(SelectedItemsProperty, value ?? Array.Empty()); + get => (ISet?)GetValue(SelectedItemsProperty); + set => SetValue(SelectedItemsProperty, value ?? new HashSet()); } public static readonly BindableProperty SelectedItemProperty = @@ -272,7 +272,7 @@ public IList? SelectedItems if (newValue is null || newValue is not ItemPosition) vlv.SelectedItems = null; else if (newValue is ItemPosition p) - vlv.SelectedItems = new[] { p }; + vlv.SelectedItems = new HashSet(){p}; } }); @@ -294,11 +294,11 @@ public void DeselectItem(ItemPosition itemPosition) } else if (SelectionMode == Maui.SelectionMode.Multiple) { - var current = SelectedItems.ToList(); - if (current.Contains(itemPosition)) + if (SelectedItems?.Contains(itemPosition) ?? false) { + var current = SelectedItems.ToHashSet(); current.Remove(itemPosition); - SelectedItems = current.ToArray(); + SelectedItems = current; } } } @@ -314,10 +314,26 @@ public void SelectItem(ItemPosition itemPosition) } else if (SelectionMode == Maui.SelectionMode.Multiple) { - var current = SelectedItems; - if (current is null || !current.Contains(itemPosition)) + if (!(SelectedItems?.Contains(itemPosition) ?? false)) { - SelectedItems = (current ?? []).Append(itemPosition).ToArray(); + var current = SelectedItems?.ToHashSet() ?? []; + current.Add(itemPosition); + SelectedItems = current; + } + } + } + + public void SelectMany(IEnumerable items) + { + if (SelectionMode == Maui.SelectionMode.Multiple) + { + if (items.Any(i => !(SelectedItems?.Contains(i) ?? false))) + { + var current = (SelectedItems ?? Enumerable.Empty()) + .Concat(items) + .ToHashSet(); + + SelectedItems = current; } } } diff --git a/VirtualListView/IVirtualListView.cs b/VirtualListView/IVirtualListView.cs index 8d739e7..f45514d 100644 --- a/VirtualListView/IVirtualListView.cs +++ b/VirtualListView/IVirtualListView.cs @@ -22,7 +22,7 @@ public interface IVirtualListView : IView SelectionMode SelectionMode { get; } - IList SelectedItems { get; set; } + ISet SelectedItems { get; set; } ItemPosition? SelectedItem { get; set; } diff --git a/VirtualListView/ItemPosition.cs b/VirtualListView/ItemPosition.cs index 68022f9..17872d3 100644 --- a/VirtualListView/ItemPosition.cs +++ b/VirtualListView/ItemPosition.cs @@ -15,4 +15,6 @@ public ItemPosition(int sectionIndex = 0, int itemIndex = 0) public bool Equals(ItemPosition other) => SectionIndex == other.SectionIndex && ItemIndex == other.ItemIndex; + public override int GetHashCode() + => SectionIndex * 16 + ItemIndex; } \ No newline at end of file diff --git a/VirtualListView/VirtualListViewHandler.cs b/VirtualListView/VirtualListViewHandler.cs index 79cf0bd..a758c8a 100644 --- a/VirtualListView/VirtualListViewHandler.cs +++ b/VirtualListView/VirtualListViewHandler.cs @@ -97,36 +97,33 @@ public bool IsItemSelected(int sectionIndex, int itemIndex) return previousSelections.Contains(new ItemPosition(sectionIndex, itemIndex)); } - ItemPosition[] previousSelections = Array.Empty(); + HashSet previousSelections = []; public static void MapSelectedItems(VirtualListViewHandler handler, IVirtualListView virtualListView) { if (handler is null) return; - var newSelections = virtualListView?.SelectedItems ?? Array.Empty(); + ISet newSelections = virtualListView?.SelectedItems ?? new HashSet(); if (virtualListView.SelectionMode == SelectionMode.None) - newSelections = Array.Empty(); + newSelections = new HashSet(); else if (virtualListView.SelectionMode == SelectionMode.Single && newSelections.Count > 1) - newSelections = newSelections.Take(1).ToArray(); + newSelections = newSelections.Take(1).ToHashSet(); - // First deselect any previously selected items that aren't in the new set - foreach (var itemPosition in handler.previousSelections) + var changed = new HashSet(handler.previousSelections); + changed.SymmetricExceptWith(newSelections); + foreach (var itemPosition in changed) { - if (!newSelections.Contains(itemPosition)) + if (handler.previousSelections.Contains(itemPosition)) + // Deselect any previously selected items that aren't in the new set handler.PlatformUpdateItemSelection(itemPosition, false); - } - - // Set all the new state selected to true - foreach (var itemPosition in newSelections) - { - if (!handler.previousSelections.Contains(itemPosition)) + else + // Set all the new state selected to true handler.PlatformUpdateItemSelection(itemPosition, true); } - // Keep track of the new state for next time it changes - handler.previousSelections = newSelections.ToArray(); + handler.previousSelections = new HashSet(newSelections); } public static void MapIsHeaderVisible(VirtualListViewHandler handler, IVirtualListView virtualListView)