Skip to content

Commit d183b14

Browse files
authored
Merge pull request #303 from AvaloniaUI/fixes/drag-drop-not-updating
Handle focused item being removed when outside the viewport.
2 parents 38dce08 + a4bacae commit d183b14

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

samples/TreeDataGridDemo/App.axaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class App : Application
99
public override void Initialize()
1010
{
1111
AvaloniaXamlLoader.Load(this);
12+
Bogus.Randomizer.Seed = new System.Random(0);
1213
}
1314

1415
public override void OnFrameworkInitializationCompleted()

src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,13 @@ private void RecycleElement(Control element, int index)
663663

664664
private void RecycleElementOnItemRemoved(Control element)
665665
{
666+
if (element == _focusedElement)
667+
{
668+
_focusedElement.LostFocus -= OnUnrealizedFocusedElementLostFocus;
669+
_focusedElement = null;
670+
_focusedIndex = -1;
671+
}
672+
666673
UnrealizeElementOnItemRemoved(element);
667674
element.IsVisible = false;
668675
ElementFactory!.RecycleElement(element);
@@ -691,6 +698,12 @@ private void TrimUnrealizedChildren()
691698

692699
private void OnItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
693700
{
701+
void ClearFocusedElement(int index, int count)
702+
{
703+
if (_focusedElement is not null && _focusedIndex >= index && _focusedIndex < index + count)
704+
RecycleElementOnItemRemoved(_focusedElement);
705+
}
706+
694707
InvalidateMeasure();
695708

696709
if (_realizedElements is null)
@@ -703,16 +716,21 @@ private void OnItemsCollectionChanged(object? sender, NotifyCollectionChangedEve
703716
break;
704717
case NotifyCollectionChangedAction.Remove:
705718
_realizedElements.ItemsRemoved(e.OldStartingIndex, e.OldItems!.Count, _updateElementIndex, _recycleElementOnItemRemoved);
719+
ClearFocusedElement(e.OldStartingIndex, e.OldItems!.Count);
706720
break;
707721
case NotifyCollectionChangedAction.Replace:
708722
_realizedElements.ItemsReplaced(e.OldStartingIndex, e.OldItems!.Count, _recycleElementOnItemRemoved);
723+
ClearFocusedElement(e.OldStartingIndex, e.OldItems!.Count);
709724
break;
710725
case NotifyCollectionChangedAction.Move:
711726
_realizedElements.ItemsRemoved(e.OldStartingIndex, e.OldItems!.Count, _updateElementIndex, _recycleElementOnItemRemoved);
712727
_realizedElements.ItemsInserted(e.NewStartingIndex, e.NewItems!.Count, _updateElementIndex);
728+
ClearFocusedElement(e.OldStartingIndex, e.OldItems!.Count);
713729
break;
714730
case NotifyCollectionChangedAction.Reset:
715731
_realizedElements.ItemsReset(_recycleElementOnItemRemoved);
732+
if (_focusedElement is not null )
733+
RecycleElementOnItemRemoved(_focusedElement);
716734
break;
717735
}
718736
}

tests/Avalonia.Controls.TreeDataGrid.Tests/Primitives/TreeDataGridRowsPresenterTests.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,78 @@ public void Handles_Removing_Row_Range_That_Invalidates_Current_Viewport()
352352
Assert.Equal(new Size(100, 100), target.Bounds.Size);
353353
}
354354

355+
[AvaloniaFact(Timeout = 10000)]
356+
public void Handles_Removing_Focused_Row_While_Outside_Viewport()
357+
{
358+
var (target, scroll, items) = CreateTarget();
359+
var element = target.RealizedElements.ElementAt(0)!;
360+
361+
element.Focusable = true;
362+
element.Focus();
363+
364+
// Scroll down one item.
365+
scroll.Offset = new Vector(0, 10);
366+
Layout(target);
367+
368+
// Remove the focused element.
369+
items.RemoveAt(0);
370+
371+
// Scroll back to the beginning.
372+
scroll.Offset = new Vector(0, 0);
373+
Layout(target);
374+
375+
// The correct element should be shown.
376+
Assert.Same(items[0], target.RealizedElements.ElementAt(0)!.DataContext);
377+
}
378+
379+
[AvaloniaFact(Timeout = 10000)]
380+
public void Handles_Replacing_Focused_Row_While_Outside_Viewport()
381+
{
382+
var (target, scroll, items) = CreateTarget();
383+
var element = target.RealizedElements.ElementAt(0)!;
384+
385+
element.Focusable = true;
386+
element.Focus();
387+
388+
// Scroll down one item.
389+
scroll.Offset = new Vector(0, 10);
390+
Layout(target);
391+
392+
// Replace the focused element.
393+
items[0] = new Model { Id = 100, Title = "New Item" };
394+
395+
// Scroll back to the beginning.
396+
scroll.Offset = new Vector(0, 0);
397+
Layout(target);
398+
399+
// The correct element should be shown.
400+
Assert.Same(items[0], target.RealizedElements.ElementAt(0)!.DataContext);
401+
}
402+
403+
[AvaloniaFact(Timeout = 10000)]
404+
public void Handles_Moving_Focused_Row_While_Outside_Viewport()
405+
{
406+
var (target, scroll, items) = CreateTarget();
407+
var element = target.RealizedElements.ElementAt(0)!;
408+
409+
element.Focusable = true;
410+
element.Focus();
411+
412+
// Scroll down one item.
413+
scroll.Offset = new Vector(0, 10);
414+
Layout(target);
415+
416+
// Move the focused element.
417+
items.Move(0, items.Count - 1);
418+
419+
// Scroll back to the beginning.
420+
scroll.Offset = new Vector(0, 0);
421+
Layout(target);
422+
423+
// The correct element should be shown.
424+
Assert.Same(items[0], target.RealizedElements.ElementAt(0)!.DataContext);
425+
}
426+
355427
[AvaloniaFact(Timeout = 10000)]
356428
public void Updates_Star_Column_ActualWidth()
357429
{

0 commit comments

Comments
 (0)