diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index bbea3693cc..0e696e0199 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -362,7 +362,7 @@ namespace Avalonia } /// - bool IResourceProvider.TryGetResource(string key, out object value) + bool IResourceProvider.TryGetResource(object key, out object value) { value = null; return (_resources?.TryGetResource(key, out value) ?? false) || diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index 280c3ad93a..dcde8117f6 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -644,20 +644,20 @@ namespace Avalonia.Controls.Primitives /// The desired items. internal static void SynchronizeItems(IList items, IEnumerable desired) { - int index = 0; + var index = 0; - foreach (var i in desired) + foreach (object item in desired) { - if (index < items.Count) + int itemIndex = items.IndexOf(item); + + if (itemIndex == -1) { - if (items[index] != i) - { - items[index] = i; - } + items.Insert(index, item); } - else + else if(itemIndex != index) { - items.Add(i); + items.RemoveAt(itemIndex); + items.Insert(index, item); } ++index; diff --git a/src/Avalonia.Styling/Controls/IResourceProvider.cs b/src/Avalonia.Styling/Controls/IResourceProvider.cs index eec783623c..cbaacee012 100644 --- a/src/Avalonia.Styling/Controls/IResourceProvider.cs +++ b/src/Avalonia.Styling/Controls/IResourceProvider.cs @@ -28,6 +28,6 @@ namespace Avalonia.Controls /// /// True if the resource if found, otherwise false. /// - bool TryGetResource(string key, out object value); + bool TryGetResource(object key, out object value); } } diff --git a/src/Avalonia.Styling/Controls/ResourceDictionary.cs b/src/Avalonia.Styling/Controls/ResourceDictionary.cs index 74a861b36b..901e27b7b7 100644 --- a/src/Avalonia.Styling/Controls/ResourceDictionary.cs +++ b/src/Avalonia.Styling/Controls/ResourceDictionary.cs @@ -69,7 +69,7 @@ namespace Avalonia.Controls } /// - public bool TryGetResource(string key, out object value) + public bool TryGetResource(object key, out object value) { if (TryGetValue(key, out value)) { diff --git a/src/Avalonia.Styling/Controls/ResourceProviderExtensions.cs b/src/Avalonia.Styling/Controls/ResourceProviderExtensions.cs index 52309b87a2..01112eaf2c 100644 --- a/src/Avalonia.Styling/Controls/ResourceProviderExtensions.cs +++ b/src/Avalonia.Styling/Controls/ResourceProviderExtensions.cs @@ -11,7 +11,7 @@ namespace Avalonia.Controls /// The control. /// The resource key. /// The resource, or if not found. - public static object FindResource(this IResourceNode control, string key) + public static object FindResource(this IResourceNode control, object key) { if (control.TryFindResource(key, out var value)) { @@ -28,7 +28,7 @@ namespace Avalonia.Controls /// The resource key. /// On return, contains the resource if found, otherwise null. /// True if the resource was found; otherwise false. - public static bool TryFindResource(this IResourceNode control, string key, out object value) + public static bool TryFindResource(this IResourceNode control, object key, out object value) { Contract.Requires(control != null); Contract.Requires(key != null); @@ -52,7 +52,7 @@ namespace Avalonia.Controls return false; } - public static IObservable GetResourceObservable(this IResourceNode target, string key) + public static IObservable GetResourceObservable(this IResourceNode target, object key) { return new ResourceObservable(target, key); } @@ -60,9 +60,9 @@ namespace Avalonia.Controls private class ResourceObservable : LightweightObservableBase { private readonly IResourceNode _target; - private readonly string _key; + private readonly object _key; - public ResourceObservable(IResourceNode target, string key) + public ResourceObservable(IResourceNode target, object key) { _target = target; _key = key; diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index d314a8d44e..6361763614 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -415,7 +415,7 @@ namespace Avalonia } /// - bool IResourceProvider.TryGetResource(string key, out object value) + bool IResourceProvider.TryGetResource(object key, out object value) { value = null; return (_resources?.TryGetResource(key, out value) ?? false) || diff --git a/src/Avalonia.Styling/Styling/Style.cs b/src/Avalonia.Styling/Styling/Style.cs index d799df7ac9..3ce82b4160 100644 --- a/src/Avalonia.Styling/Styling/Style.cs +++ b/src/Avalonia.Styling/Styling/Style.cs @@ -171,7 +171,7 @@ namespace Avalonia.Styling } /// - public bool TryGetResource(string key, out object result) + public bool TryGetResource(object key, out object result) { result = null; return _resources?.TryGetResource(key, out result) ?? false; diff --git a/src/Avalonia.Styling/Styling/Styles.cs b/src/Avalonia.Styling/Styling/Styles.cs index 288cf35d08..789bb6ffd3 100644 --- a/src/Avalonia.Styling/Styling/Styles.cs +++ b/src/Avalonia.Styling/Styling/Styles.cs @@ -178,7 +178,7 @@ namespace Avalonia.Styling } /// - public bool TryGetResource(string key, out object value) + public bool TryGetResource(object key, out object value) { if (_resources != null && _resources.TryGetValue(key, out value)) { diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs index 5f0e84c63a..48e55dc251 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs @@ -26,7 +26,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions ResourceKey = resourceKey; } - public string ResourceKey { get; set; } + public object ResourceKey { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) => ProvideTypedValue(serviceProvider); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs index 827f58a909..323a341f6a 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs @@ -47,7 +47,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions bool IResourceProvider.HasResources => Loaded.HasResources; /// - bool IResourceProvider.TryGetResource(string key, out object value) + bool IResourceProvider.TryGetResource(object key, out object value) { return Loaded.TryGetResource(key, out value); } diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs index 01ec9753bd..7acee50d80 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs @@ -86,7 +86,7 @@ namespace Avalonia.Markup.Xaml.Styling } /// - public bool TryGetResource(string key, out object value) => Loaded.TryGetResource(key, out value); + public bool TryGetResource(object key, out object value) => Loaded.TryGetResource(key, out value); /// void ISetStyleParent.NotifyResourcesChanged(ResourcesChangedEventArgs e) diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index 519872f9f2..15081b184c 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -10,6 +10,7 @@ using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Data.Core; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.LogicalTree; using Avalonia.UnitTests; using Xunit; @@ -425,7 +426,6 @@ namespace Avalonia.Controls.UnitTests Assert.True(called); } - [Fact] public void LogicalChildren_Should_Be_Set() { @@ -623,6 +623,135 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Pressing_SelectAll_Gesture_Should_Select_All_Nodes() + { + using (UnitTestApplication.Start()) + { + var tree = CreateTestTreeData(); + var target = new TreeView + { + Template = CreateTreeViewTemplate(), + Items = tree, + SelectionMode = SelectionMode.Multiple + }; + + var visualRoot = new TestRoot(); + visualRoot.Child = target; + + CreateNodeDataTemplate(target); + ApplyTemplates(target); + + var rootNode = tree[0]; + + var keymap = AvaloniaLocator.Current.GetService(); + var selectAllGesture = keymap.SelectAll.First(); + + var keyEvent = new KeyEventArgs + { + RoutedEvent = InputElement.KeyDownEvent, + Key = selectAllGesture.Key, + Modifiers = selectAllGesture.Modifiers + }; + + target.RaiseEvent(keyEvent); + + TreeTestHelper.AssertChildrenSelected(target, rootNode); + } + } + + [Fact] + public void Pressing_SelectAll_Gesture_With_Downward_Range_Selected_Should_Select_All_Nodes() + { + using (UnitTestApplication.Start()) + { + var tree = CreateTestTreeData(); + var target = new TreeView + { + Template = CreateTreeViewTemplate(), + Items = tree, + SelectionMode = SelectionMode.Multiple + }; + + var visualRoot = new TestRoot(); + visualRoot.Child = target; + + CreateNodeDataTemplate(target); + ApplyTemplates(target); + + var rootNode = tree[0]; + + var from = rootNode.Children[0]; + var to = rootNode.Children.Last(); + + var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from); + var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to); + + TreeTestHelper.ClickContainer(fromContainer, InputModifiers.None); + TreeTestHelper.ClickContainer(toContainer, InputModifiers.Shift); + + var keymap = AvaloniaLocator.Current.GetService(); + var selectAllGesture = keymap.SelectAll.First(); + + var keyEvent = new KeyEventArgs + { + RoutedEvent = InputElement.KeyDownEvent, + Key = selectAllGesture.Key, + Modifiers = selectAllGesture.Modifiers + }; + + target.RaiseEvent(keyEvent); + + TreeTestHelper.AssertChildrenSelected(target, rootNode); + } + } + + [Fact] + public void Pressing_SelectAll_Gesture_With_Upward_Range_Selected_Should_Select_All_Nodes() + { + using (UnitTestApplication.Start()) + { + var tree = CreateTestTreeData(); + var target = new TreeView + { + Template = CreateTreeViewTemplate(), + Items = tree, + SelectionMode = SelectionMode.Multiple + }; + + var visualRoot = new TestRoot(); + visualRoot.Child = target; + + CreateNodeDataTemplate(target); + ApplyTemplates(target); + + var rootNode = tree[0]; + + var from = rootNode.Children.Last(); + var to = rootNode.Children[0]; + + var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from); + var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to); + + TreeTestHelper.ClickContainer(fromContainer, InputModifiers.None); + TreeTestHelper.ClickContainer(toContainer, InputModifiers.Shift); + + var keymap = AvaloniaLocator.Current.GetService(); + var selectAllGesture = keymap.SelectAll.First(); + + var keyEvent = new KeyEventArgs + { + RoutedEvent = InputElement.KeyDownEvent, + Key = selectAllGesture.Key, + Modifiers = selectAllGesture.Modifiers + }; + + target.RaiseEvent(keyEvent); + + TreeTestHelper.AssertChildrenSelected(target, rootNode); + } + } + private void ApplyTemplates(TreeView tree) { tree.ApplyTemplate(); @@ -765,7 +894,7 @@ namespace Avalonia.Controls.UnitTests } } - private class Node : NotifyingBase + private class Node : NotifyingBase { private IAvaloniaList _children;