|
|
@@ -105,32 +105,21 @@ namespace Avalonia.Controls
|
|
|
get => _selectedItem;
|
|
|
set
|
|
|
{
|
|
|
- SetAndRaise(SelectedItemProperty, ref _selectedItem,
|
|
|
- (object val, ref object backing, Action<Action> notifyWrapper) =>
|
|
|
- {
|
|
|
- var old = backing;
|
|
|
- backing = val;
|
|
|
-
|
|
|
- notifyWrapper(() =>
|
|
|
- RaisePropertyChanged(
|
|
|
- SelectedItemProperty,
|
|
|
- old,
|
|
|
- val));
|
|
|
+ SetAndRaise(SelectedItemProperty, ref _selectedItem, value);
|
|
|
|
|
|
- if (val != null)
|
|
|
- {
|
|
|
- if (SelectedItems.Count != 1 || SelectedItems[0] != val)
|
|
|
- {
|
|
|
- _syncingSelectedItems = true;
|
|
|
- SelectSingleItem(val);
|
|
|
- _syncingSelectedItems = false;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (SelectedItems.Count > 0)
|
|
|
- {
|
|
|
- SelectedItems.Clear();
|
|
|
- }
|
|
|
- }, value);
|
|
|
+ if (value != null)
|
|
|
+ {
|
|
|
+ if (SelectedItems.Count != 1 || SelectedItems[0] != value)
|
|
|
+ {
|
|
|
+ _syncingSelectedItems = true;
|
|
|
+ SelectSingleItem(value);
|
|
|
+ _syncingSelectedItems = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (SelectedItems.Count > 0)
|
|
|
+ {
|
|
|
+ SelectedItems.Clear();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -164,6 +153,48 @@ namespace Avalonia.Controls
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Expands the specified <see cref="TreeViewItem"/> all descendent <see cref="TreeViewItem"/>s.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="item">The item to expand.</param>
|
|
|
+ public void ExpandSubTree(TreeViewItem item)
|
|
|
+ {
|
|
|
+ item.IsExpanded = true;
|
|
|
+
|
|
|
+ var panel = item.Presenter.Panel;
|
|
|
+
|
|
|
+ if (panel != null)
|
|
|
+ {
|
|
|
+ foreach (var child in panel.Children)
|
|
|
+ {
|
|
|
+ if (child is TreeViewItem treeViewItem)
|
|
|
+ {
|
|
|
+ ExpandSubTree(treeViewItem);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Selects all items in the <see cref="TreeView"/>.
|
|
|
+ /// </summary>
|
|
|
+ /// <remarks>
|
|
|
+ /// Note that this method only selects nodes currently visible due to their parent nodes
|
|
|
+ /// being expanded: it does not expand nodes.
|
|
|
+ /// </remarks>
|
|
|
+ public void SelectAll()
|
|
|
+ {
|
|
|
+ SynchronizeItems(SelectedItems, ItemContainerGenerator.Index.Items);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Deselects all items in the <see cref="TreeView"/>.
|
|
|
+ /// </summary>
|
|
|
+ public void UnselectAll()
|
|
|
+ {
|
|
|
+ SelectedItems.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Subscribes to the <see cref="SelectedItems"/> CollectionChanged event, if any.
|
|
|
/// </summary>
|
|
|
@@ -409,7 +440,7 @@ namespace Avalonia.Controls
|
|
|
|
|
|
if (this.SelectionMode == SelectionMode.Multiple && Match(keymap.SelectAll))
|
|
|
{
|
|
|
- SynchronizeItems(SelectedItems, ItemContainerGenerator.Index.Items);
|
|
|
+ SelectAll();
|
|
|
e.Handled = true;
|
|
|
}
|
|
|
}
|
|
|
@@ -479,7 +510,8 @@ namespace Avalonia.Controls
|
|
|
e.Source,
|
|
|
true,
|
|
|
(e.InputModifiers & InputModifiers.Shift) != 0,
|
|
|
- (e.InputModifiers & InputModifiers.Control) != 0);
|
|
|
+ (e.InputModifiers & InputModifiers.Control) != 0,
|
|
|
+ e.MouseButton == MouseButton.Right);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -490,11 +522,13 @@ namespace Avalonia.Controls
|
|
|
/// <param name="select">Whether the item should be selected or unselected.</param>
|
|
|
/// <param name="rangeModifier">Whether the range modifier is enabled (i.e. shift key).</param>
|
|
|
/// <param name="toggleModifier">Whether the toggle modifier is enabled (i.e. ctrl key).</param>
|
|
|
+ /// <param name="rightButton">Whether the event is a right-click.</param>
|
|
|
protected void UpdateSelectionFromContainer(
|
|
|
IControl container,
|
|
|
bool select = true,
|
|
|
bool rangeModifier = false,
|
|
|
- bool toggleModifier = false)
|
|
|
+ bool toggleModifier = false,
|
|
|
+ bool rightButton = false)
|
|
|
{
|
|
|
var item = ItemContainerGenerator.Index.ItemFromContainer(container);
|
|
|
|
|
|
@@ -515,7 +549,14 @@ namespace Avalonia.Controls
|
|
|
var multi = (mode & SelectionMode.Multiple) != 0;
|
|
|
var range = multi && selectedContainer != null && rangeModifier;
|
|
|
|
|
|
- if (!toggle && !range)
|
|
|
+ if (rightButton)
|
|
|
+ {
|
|
|
+ if (!SelectedItems.Contains(item))
|
|
|
+ {
|
|
|
+ SelectSingleItem(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (!toggle && !range)
|
|
|
{
|
|
|
SelectSingleItem(item);
|
|
|
}
|
|
|
@@ -684,6 +725,7 @@ namespace Avalonia.Controls
|
|
|
/// <param name="select">Whether the container should be selected or unselected.</param>
|
|
|
/// <param name="rangeModifier">Whether the range modifier is enabled (i.e. shift key).</param>
|
|
|
/// <param name="toggleModifier">Whether the toggle modifier is enabled (i.e. ctrl key).</param>
|
|
|
+ /// <param name="rightButton">Whether the event is a right-click.</param>
|
|
|
/// <returns>
|
|
|
/// True if the event originated from a container that belongs to the control; otherwise
|
|
|
/// false.
|
|
|
@@ -692,13 +734,14 @@ namespace Avalonia.Controls
|
|
|
IInteractive eventSource,
|
|
|
bool select = true,
|
|
|
bool rangeModifier = false,
|
|
|
- bool toggleModifier = false)
|
|
|
+ bool toggleModifier = false,
|
|
|
+ bool rightButton = false)
|
|
|
{
|
|
|
var container = GetContainerFromEventSource(eventSource);
|
|
|
|
|
|
if (container != null)
|
|
|
{
|
|
|
- UpdateSelectionFromContainer(container, select, rangeModifier, toggleModifier);
|
|
|
+ UpdateSelectionFromContainer(container, select, rangeModifier, toggleModifier, rightButton);
|
|
|
return true;
|
|
|
}
|
|
|
|