|
|
|
@ -2,6 +2,7 @@ |
|
|
|
using System.Collections; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections.Specialized; |
|
|
|
using System.Linq; |
|
|
|
using Avalonia.Controls.Utils; |
|
|
|
|
|
|
|
#nullable enable |
|
|
|
@ -234,6 +235,11 @@ namespace Avalonia.Controls.Selection |
|
|
|
var shiftIndex = -1; |
|
|
|
List<T>? removed = null; |
|
|
|
|
|
|
|
if (!IsValidCollectionChange(e)) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
switch (e.Action) |
|
|
|
{ |
|
|
|
case NotifyCollectionChangedAction.Add: |
|
|
|
@ -276,6 +282,34 @@ namespace Avalonia.Controls.Selection |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private protected virtual bool IsValidCollectionChange(NotifyCollectionChangedEventArgs e) |
|
|
|
{ |
|
|
|
// If the selection is modified in a CollectionChanged handler before the selection
|
|
|
|
// model's CollectionChanged handler has had chance to run then we can end up with
|
|
|
|
// a selected index that refers to the *new* state of the Source intermixed with
|
|
|
|
// indexes that reference an old state of the source.
|
|
|
|
//
|
|
|
|
// There's not much we can do in this situation, so detect whether shifting the
|
|
|
|
// current selected indexes would result in an invalid index in the source, and if
|
|
|
|
// so bail.
|
|
|
|
//
|
|
|
|
// See unit test Handles_Selection_Made_In_CollectionChanged for more details.
|
|
|
|
if (ItemsView is object && |
|
|
|
RangesEnabled && |
|
|
|
Ranges.Count > 0 && |
|
|
|
e.Action == NotifyCollectionChangedAction.Add) |
|
|
|
{ |
|
|
|
var lastIndex = Ranges.Last().End; |
|
|
|
|
|
|
|
if (e.NewStartingIndex <= lastIndex) |
|
|
|
{ |
|
|
|
return lastIndex + e.NewItems.Count < ItemsView.Count; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
private protected struct CollectionChangeState |
|
|
|
{ |
|
|
|
public int ShiftIndex; |
|
|
|
|