|
|
|
@ -5,6 +5,7 @@ using System.ComponentModel; |
|
|
|
using System.Linq; |
|
|
|
using Avalonia.Collections; |
|
|
|
using Avalonia.Controls.Presenters; |
|
|
|
using Avalonia.Controls.Primitives; |
|
|
|
using Avalonia.Controls.Templates; |
|
|
|
using Avalonia.Data; |
|
|
|
using Avalonia.Data.Core; |
|
|
|
@ -219,7 +220,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
Assert.True(fromContainer.IsSelected); |
|
|
|
|
|
|
|
ClickContainer(toContainer, KeyModifiers.Shift); |
|
|
|
AssertChildrenSelected(target, rootNode); |
|
|
|
AssertAllChildContainersSelected(target, rootNode); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -238,7 +239,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
Assert.True(fromContainer.IsSelected); |
|
|
|
|
|
|
|
ClickContainer(toContainer, KeyModifiers.Shift); |
|
|
|
AssertChildrenSelected(target, rootNode); |
|
|
|
AssertAllChildContainersSelected(target, rootNode); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -255,7 +256,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
|
|
|
|
ClickContainer(fromContainer, KeyModifiers.None); |
|
|
|
ClickContainer(toContainer, KeyModifiers.Shift); |
|
|
|
AssertChildrenSelected(target, rootNode); |
|
|
|
AssertAllChildContainersSelected(target, rootNode); |
|
|
|
|
|
|
|
ClickContainer(fromContainer, KeyModifiers.None); |
|
|
|
Assert.True(fromContainer.IsSelected); |
|
|
|
@ -975,7 +976,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
|
|
|
|
target.RaiseEvent(keyEvent); |
|
|
|
|
|
|
|
AssertChildrenSelected(target, rootNode); |
|
|
|
AssertAllChildContainersSelected(target, rootNode); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -1005,7 +1006,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
|
|
|
|
target.RaiseEvent(keyEvent); |
|
|
|
|
|
|
|
AssertChildrenSelected(target, rootNode); |
|
|
|
AssertAllChildContainersSelected(target, rootNode); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -1035,7 +1036,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
|
|
|
|
target.RaiseEvent(keyEvent); |
|
|
|
|
|
|
|
AssertChildrenSelected(target, rootNode); |
|
|
|
AssertAllChildContainersSelected(target, rootNode); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -1047,7 +1048,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
|
|
|
|
target.SelectAll(); |
|
|
|
|
|
|
|
AssertChildrenSelected(target, data[0]); |
|
|
|
AssertAllChildContainersSelected(target, data[0]); |
|
|
|
Assert.Equal(5, target.SelectedItems.Count); |
|
|
|
|
|
|
|
_mouse.Click(target.Presenter!.Panel!.Children[0], MouseButton.Right); |
|
|
|
@ -1259,6 +1260,87 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Can_Bind_Initial_Selected_State_Via_ItemContainerTheme() |
|
|
|
{ |
|
|
|
using var app = Start(); |
|
|
|
var data = CreateTestTreeData(); |
|
|
|
var selected = new[] { data[0], data[0].Children[1] }; |
|
|
|
|
|
|
|
foreach (var node in selected) |
|
|
|
node.IsSelected = true; |
|
|
|
|
|
|
|
var itemTheme = new ControlTheme(typeof(TreeViewItem)) |
|
|
|
{ |
|
|
|
BasedOn = CreateTreeViewItemControlTheme(), |
|
|
|
Setters = |
|
|
|
{ |
|
|
|
new Setter(SelectingItemsControl.IsSelectedProperty, new Binding("IsSelected")), |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var target = CreateTarget(data: data, itemContainerTheme: itemTheme); |
|
|
|
|
|
|
|
AssertDataSelection(data, selected); |
|
|
|
AssertContainerSelection(target, selected); |
|
|
|
Assert.Equal(selected[0], target.SelectedItem); |
|
|
|
Assert.Equal(selected, target.SelectedItems); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Can_Bind_Initial_Selected_State_Via_Style() |
|
|
|
{ |
|
|
|
using var app = Start(); |
|
|
|
var data = CreateTestTreeData(); |
|
|
|
var selected = new[] { data[0], data[0].Children[1] }; |
|
|
|
|
|
|
|
foreach (var node in selected) |
|
|
|
node.IsSelected = true; |
|
|
|
|
|
|
|
var style = new Style(x => x.OfType<TreeViewItem>()) |
|
|
|
{ |
|
|
|
Setters = |
|
|
|
{ |
|
|
|
new Setter(SelectingItemsControl.IsSelectedProperty, new Binding("IsSelected")), |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var target = CreateTarget(data: data, styles: new[] { style }); |
|
|
|
|
|
|
|
AssertDataSelection(data, selected); |
|
|
|
AssertContainerSelection(target, selected); |
|
|
|
Assert.Equal(selected[0], target.SelectedItem); |
|
|
|
Assert.Equal(selected, target.SelectedItems); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Selection_State_Is_Updated_Via_IsSelected_Binding() |
|
|
|
{ |
|
|
|
using var app = Start(); |
|
|
|
var data = CreateTestTreeData(); |
|
|
|
var selected = new[] { data[0], data[0].Children[1] }; |
|
|
|
|
|
|
|
selected[0].IsSelected = true; |
|
|
|
|
|
|
|
var itemTheme = new ControlTheme(typeof(TreeViewItem)) |
|
|
|
{ |
|
|
|
BasedOn = CreateTreeViewItemControlTheme(), |
|
|
|
Setters = |
|
|
|
{ |
|
|
|
new Setter(SelectingItemsControl.IsSelectedProperty, new Binding("IsSelected")), |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var target = CreateTarget(data: data, itemContainerTheme: itemTheme); |
|
|
|
|
|
|
|
selected[1].IsSelected = true; |
|
|
|
|
|
|
|
AssertDataSelection(data, selected); |
|
|
|
AssertContainerSelection(target, selected); |
|
|
|
Assert.Equal(selected[0], target.SelectedItem); |
|
|
|
Assert.Equal(selected, target.SelectedItems); |
|
|
|
} |
|
|
|
|
|
|
|
private static TreeView CreateTarget(Optional<IList<Node>?> data = default, |
|
|
|
bool expandAll = true, |
|
|
|
ControlTheme? itemContainerTheme = null, |
|
|
|
@ -1465,17 +1547,61 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
_mouse.Click(container, modifiers: modifiers); |
|
|
|
} |
|
|
|
|
|
|
|
private void AssertChildrenSelected(TreeView treeView, Node rootNode) |
|
|
|
private void AssertContainerSelection(TreeView treeView, params Node[] expected) |
|
|
|
{ |
|
|
|
Assert.NotNull(rootNode.Children); |
|
|
|
static void Evaluate(Control container, HashSet<Node> remaining) |
|
|
|
{ |
|
|
|
var treeViewItem = Assert.IsType<TreeViewItem>(container); |
|
|
|
var node = (Node)container.DataContext!; |
|
|
|
|
|
|
|
foreach (var child in rootNode.Children) |
|
|
|
Assert.Equal(remaining.Contains(node), treeViewItem.IsSelected); |
|
|
|
remaining.Remove(node); |
|
|
|
|
|
|
|
foreach (var child in treeViewItem.GetRealizedContainers()) |
|
|
|
{ |
|
|
|
Evaluate(child, remaining); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var remaining = expected.ToHashSet(); |
|
|
|
foreach (var container in treeView.GetRealizedContainers()) |
|
|
|
Evaluate(container, remaining); |
|
|
|
Assert.Empty(remaining); |
|
|
|
} |
|
|
|
|
|
|
|
private void AssertAllChildContainersSelected(TreeView treeView, Node node) |
|
|
|
{ |
|
|
|
Assert.NotNull(node.Children); |
|
|
|
|
|
|
|
foreach (var child in node.Children) |
|
|
|
{ |
|
|
|
var container = Assert.IsType<TreeViewItem>(treeView.TreeContainerFromItem(child)); |
|
|
|
Assert.True(container.IsSelected); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void AssertDataSelection(IEnumerable<Node> data, params Node[] expected) |
|
|
|
{ |
|
|
|
static void Evaluate(Node rootNode, HashSet<Node> remaining) |
|
|
|
{ |
|
|
|
Assert.Equal(remaining.Contains(rootNode), rootNode.IsSelected); |
|
|
|
remaining.Remove(rootNode); |
|
|
|
|
|
|
|
if (rootNode.Children is null) |
|
|
|
return; |
|
|
|
|
|
|
|
foreach (var child in rootNode.Children) |
|
|
|
{ |
|
|
|
Evaluate(child, remaining); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var remaining = expected.ToHashSet(); |
|
|
|
foreach (var node in data) |
|
|
|
Evaluate(node, remaining); |
|
|
|
Assert.Empty(remaining); |
|
|
|
} |
|
|
|
|
|
|
|
private IDisposable Start() |
|
|
|
{ |
|
|
|
return UnitTestApplication.Start( |
|
|
|
@ -1492,6 +1618,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
private class Node : NotifyingBase |
|
|
|
{ |
|
|
|
private IAvaloniaList<Node> _children = new AvaloniaList<Node>(); |
|
|
|
private bool _isSelected; |
|
|
|
|
|
|
|
public string? Value { get; set; } |
|
|
|
|
|
|
|
@ -1504,6 +1631,21 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
RaisePropertyChanged(nameof(Children)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public bool IsSelected |
|
|
|
{ |
|
|
|
get => _isSelected; |
|
|
|
set |
|
|
|
{ |
|
|
|
if (_isSelected != value) |
|
|
|
{ |
|
|
|
_isSelected = value; |
|
|
|
RaisePropertyChanged(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public override string ToString() => Value ?? string.Empty; |
|
|
|
} |
|
|
|
|
|
|
|
private class TestTreeDataTemplate : ITreeDataTemplate |
|
|
|
|