diff --git a/src/Avalonia.Controls/SelectedItemChangedEventArgs.cs b/src/Avalonia.Controls/SelectedItemChangedEventArgs.cs
new file mode 100644
index 0000000000..6fb8a2d313
--- /dev/null
+++ b/src/Avalonia.Controls/SelectedItemChangedEventArgs.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using Avalonia;
+using Avalonia.Interactivity;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Provides data for the event.
+ ///
+ public class SelectedItemChangedEventArgs : RoutedEventArgs
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The event being raised.
+ /// The items added to the selection.
+ /// The items removed from the selection.
+ public SelectedItemChangedEventArgs(RoutedEvent routedEvent, object newItem, object oldItem)
+ : base(routedEvent)
+ {
+ NewItem = newItem;
+ OldItem = oldItem;
+ }
+
+ ///
+ /// Gets the items that were added to the selection.
+ ///
+ public object NewItem { get; }
+
+ ///
+ /// Gets the items that were removed from the selection.
+ ///
+ public object OldItem { get; }
+ }
+}
diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index 2e1c011685..50b45cbb9a 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -32,6 +32,14 @@ namespace Avalonia.Controls
o => o.SelectedItem,
(o, v) => o.SelectedItem = v);
+ ///
+ /// Defines the event.
+ ///
+ public static readonly RoutedEvent SelectedItemChangedEvent =
+ RoutedEvent.Register(
+ "SelectedItemChanged",
+ RoutingStrategies.Bubble);
+
private object _selectedItem;
///
@@ -42,6 +50,15 @@ namespace Avalonia.Controls
// HACK: Needed or SelectedItem property will not be found in Release build.
}
+ ///
+ /// Occurs when the control's selection changes.
+ ///
+ public event EventHandler SelectedItemChanged
+ {
+ add { AddHandler(SelectedItemChangedEvent, value); }
+ remove { RemoveHandler(SelectedItemChangedEvent, value); }
+ }
+
///
/// Gets the for the tree view.
///
@@ -75,6 +92,7 @@ namespace Avalonia.Controls
MarkContainerSelected(container, false);
}
+ var oldItem = _selectedItem;
SetAndRaise(SelectedItemProperty, ref _selectedItem, value);
if (_selectedItem != null)
@@ -87,6 +105,15 @@ namespace Avalonia.Controls
container.BringIntoView();
}
}
+
+ if (oldItem != _selectedItem)
+ {
+ var changed = new SelectedItemChangedEventArgs(
+ SelectedItemChangedEvent,
+ _selectedItem,
+ oldItem);
+ RaiseEvent(changed);
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
index c49c343a45..8295409f7e 100644
--- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
@@ -166,6 +166,38 @@ namespace Avalonia.Controls.UnitTests
Assert.True(container.IsSelected);
}
+
+ [Fact]
+ public void Setting_SelectedItem_Should_Raise_SelectedItemChanged_Event()
+ {
+ var tree = CreateTestTreeData();
+ var target = new TreeView
+ {
+ Template = CreateTreeViewTemplate(),
+ Items = tree,
+ };
+
+ var visualRoot = new TestRoot();
+ visualRoot.Child = target;
+
+ CreateNodeDataTemplate(target);
+ ApplyTemplates(target);
+
+ var item = tree[0].Children[1].Children[0];
+
+ var called = false;
+ target.SelectedItemChanged += (s, e) =>
+ {
+ Assert.Null(e.OldItem);
+ Assert.Same(item, e.NewItem);
+ called = true;
+ };
+
+ target.SelectedItem = item;
+ Assert.True(called);
+ }
+
+
[Fact]
public void LogicalChildren_Should_Be_Set()
{