Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions VirtualListView/Controls/VirtualListView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,20 +247,20 @@ public ICommand? ScrolledCommand
}

public static readonly BindableProperty SelectedItemsProperty =
BindableProperty.Create(nameof(SelectedItems), typeof(IList<ItemPosition>), typeof(VirtualListView), Array.Empty<ItemPosition>(),
BindableProperty.Create(nameof(SelectedItems), typeof(ISet<ItemPosition>), typeof(VirtualListView), new HashSet<ItemPosition>(),
propertyChanged: (bindableObj, oldValue, newValue) =>
{
if (bindableObj is VirtualListView vlv
&& oldValue is IList<ItemPosition> oldSelection
&& newValue is IList<ItemPosition> newSelection)
&& oldValue is ISet<ItemPosition> oldSelection
&& newValue is ISet<ItemPosition> newSelection)
{
vlv.RaiseSelectedItemsChanged(oldSelection.ToArray(), newSelection.ToArray());
}
});
public IList<ItemPosition>? SelectedItems
public ISet<ItemPosition>? SelectedItems
{
get => (IList<ItemPosition>)GetValue(SelectedItemsProperty);
set => SetValue(SelectedItemsProperty, value ?? Array.Empty<ItemPosition>());
get => (ISet<ItemPosition>?)GetValue(SelectedItemsProperty);
set => SetValue(SelectedItemsProperty, value ?? new HashSet<ItemPosition>());
}

public static readonly BindableProperty SelectedItemProperty =
Expand All @@ -272,7 +272,7 @@ public IList<ItemPosition>? 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<ItemPosition>(){p};
}
});

Expand All @@ -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;
}
}
}
Expand All @@ -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<ItemPosition> items)
{
if (SelectionMode == Maui.SelectionMode.Multiple)
{
if (items.Any(i => !(SelectedItems?.Contains(i) ?? false)))
{
var current = (SelectedItems ?? Enumerable.Empty<ItemPosition>())
.Concat(items)
.ToHashSet();

SelectedItems = current;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion VirtualListView/IVirtualListView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface IVirtualListView : IView

SelectionMode SelectionMode { get; }

IList<ItemPosition> SelectedItems { get; set; }
ISet<ItemPosition> SelectedItems { get; set; }

ItemPosition? SelectedItem { get; set; }

Expand Down
2 changes: 2 additions & 0 deletions VirtualListView/ItemPosition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
27 changes: 12 additions & 15 deletions VirtualListView/VirtualListViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,36 +97,33 @@ public bool IsItemSelected(int sectionIndex, int itemIndex)
return previousSelections.Contains(new ItemPosition(sectionIndex, itemIndex));
}

ItemPosition[] previousSelections = Array.Empty<ItemPosition>();
HashSet<ItemPosition> previousSelections = [];

public static void MapSelectedItems(VirtualListViewHandler handler, IVirtualListView virtualListView)
{
if (handler is null)
return;

var newSelections = virtualListView?.SelectedItems ?? Array.Empty<ItemPosition>();
ISet<ItemPosition> newSelections = virtualListView?.SelectedItems ?? new HashSet<ItemPosition>();

if (virtualListView.SelectionMode == SelectionMode.None)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a small refactoring suggestion, as i wonder if this needs to be checked for null as well? I Mean when virtualListView is null, it throws a NullReferenceException.
So in the current state when we have a virtualListView of null we have a new HashSet on Line 107 but cannot continue, as it should throw an exception on Line 109/111

Suggested change
if (virtualListView.SelectionMode == SelectionMode.None)
if (virtualListView?.SelectionMode == SelectionMode.None)

newSelections = Array.Empty<ItemPosition>();
newSelections = new HashSet<ItemPosition>();
else if (virtualListView.SelectionMode == SelectionMode.Single && newSelections.Count > 1)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the same problem here

Suggested change
else if (virtualListView.SelectionMode == SelectionMode.Single && newSelections.Count > 1)
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<ItemPosition>(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<ItemPosition>(newSelections);
}

public static void MapIsHeaderVisible(VirtualListViewHandler handler, IVirtualListView virtualListView)
Expand Down