diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index 0d5a453141..ef10dcdb22 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -293,6 +293,23 @@ namespace Avalonia.Controls
return TreeItemFromContainer(this, container);
}
+ private protected override void OnItemsViewCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
+ {
+ base.OnItemsViewCollectionChanged(sender, e);
+
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Remove:
+ case NotifyCollectionChangedAction.Replace:
+ foreach (var i in e.OldItems!)
+ SelectedItems.Remove(i);
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ SelectedItems.Clear();
+ break;
+ }
+ }
+
///
/// Subscribes to the CollectionChanged event, if any.
///
diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs
index ccd4f89204..cf12c12447 100644
--- a/src/Avalonia.Controls/TreeViewItem.cs
+++ b/src/Avalonia.Controls/TreeViewItem.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
using System.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Selection;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
@@ -289,6 +291,30 @@ namespace Avalonia.Controls
}
}
+ private protected override void OnItemsViewCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
+ {
+ base.OnItemsViewCollectionChanged(sender, e);
+
+ if (_treeView is null)
+ return;
+
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Remove:
+ case NotifyCollectionChangedAction.Replace:
+ foreach (var i in e.OldItems!)
+ _treeView.SelectedItems.Remove(i);
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ foreach (var i in GetRealizedContainers())
+ {
+ if (i is TreeViewItem tvi && tvi.IsSelected)
+ _treeView.SelectedItems.Remove(i.DataContext);
+ }
+ break;
+ }
+ }
+
private static int CalculateDistanceFromLogicalParent(ILogical? logical, int @default = -1) where T : class
{
var result = 0;
diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
index 7d290b1ec0..51300f343a 100644
--- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
@@ -724,6 +724,86 @@ namespace Avalonia.Controls.UnitTests
Assert.True(called);
}
+ [Fact]
+ public void Removing_Selected_Root_Item_Should_Clear_Selection()
+ {
+ using var app = Start();
+ var data = CreateTestTreeData();
+ var target = CreateTarget(data: data);
+ var item = data[0];
+
+ target.SelectedItem = item;
+
+ data.RemoveAt(0);
+
+ Assert.Null(target.SelectedItem);
+ Assert.Empty(target.SelectedItems);
+ }
+
+ [Fact]
+ public void Resetting_Root_Items_Should_Clear_Selection()
+ {
+ using var app = Start();
+ var data = CreateTestTreeData();
+ var target = CreateTarget(data: data);
+ var item = data[0];
+
+ target.SelectedItem = item;
+
+ data.Clear();
+
+ Assert.Null(target.SelectedItem);
+ Assert.Empty(target.SelectedItems);
+ }
+
+ [Fact]
+ public void Removing_Selected_Child_Item_Should_Clear_Selection()
+ {
+ using var app = Start();
+ var data = CreateTestTreeData();
+ var target = CreateTarget(data: data);
+ var item = data[0].Children[1];
+
+ target.SelectedItem = item;
+
+ data[0].Children.RemoveAt(1);
+
+ Assert.Null(target.SelectedItem);
+ Assert.Empty(target.SelectedItems);
+ }
+
+ [Fact]
+ public void Replacing_Selected_Child_Item_Should_Clear_Selection()
+ {
+ using var app = Start();
+ var data = CreateTestTreeData();
+ var target = CreateTarget(data: data);
+ var item = data[0].Children[1];
+
+ target.SelectedItem = item;
+
+ data[0].Children[1] = new Node();
+
+ Assert.Null(target.SelectedItem);
+ Assert.Empty(target.SelectedItems);
+ }
+
+ [Fact]
+ public void Clearing_Child_Items_Should_Clear_Selection()
+ {
+ using var app = Start();
+ var data = CreateTestTreeData();
+ var target = CreateTarget(data: data);
+ var item = data[0].Children[1];
+
+ target.SelectedItem = item;
+
+ data[0].Children.Clear();
+
+ Assert.Null(target.SelectedItem);
+ Assert.Empty(target.SelectedItems);
+ }
+
[Fact]
public void SelectedItem_Should_Be_Valid_When_SelectedItemChanged_Event_Raised()
{