From de61af19a681429f192587381907386d0e3a4416 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 11:21:59 +0200 Subject: [PATCH 01/22] Update ncrunch config. --- .ncrunch/AppWithoutLifetime.v3.ncrunchproject | 5 +++++ .../Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject | 5 +++++ .../Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 .ncrunch/AppWithoutLifetime.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject diff --git a/.ncrunch/AppWithoutLifetime.v3.ncrunchproject b/.ncrunch/AppWithoutLifetime.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/AppWithoutLifetime.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/Avalonia.Headless.NUnit.netstandard2.0.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject new file mode 100644 index 0000000000..319cd523ce --- /dev/null +++ b/.ncrunch/Avalonia.Headless.XUnit.netstandard2.0.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file From 1e5ef03eca58b391185b562b4cd1f13617c8aa04 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 10:11:12 +0200 Subject: [PATCH 02/22] Make InvalidateMirrorTransform protected. --- src/Avalonia.Base/Visual.cs | 2 +- src/Avalonia.Controls/ComboBox.cs | 2 +- src/Avalonia.Controls/TopLevel.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs index 50b23f158d..1b7975c154 100644 --- a/src/Avalonia.Base/Visual.cs +++ b/src/Avalonia.Base/Visual.cs @@ -774,7 +774,7 @@ namespace Avalonia /// Computes the value according to the /// and /// - public virtual void InvalidateMirrorTransform() + protected internal virtual void InvalidateMirrorTransform() { var flowDirection = this.FlowDirection; var parentFlowDirection = FlowDirection.LeftToRight; diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index efa319ad54..8872afab9f 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -164,7 +164,7 @@ namespace Avalonia.Controls UpdateSelectionBoxItem(SelectedItem); } - public override void InvalidateMirrorTransform() + protected internal override void InvalidateMirrorTransform() { base.InvalidateMirrorTransform(); UpdateFlowDirection(); diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 67847f621b..f655016769 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -740,7 +740,7 @@ namespace Avalonia.Controls protected override bool BypassFlowDirectionPolicies => true; - public override void InvalidateMirrorTransform() + protected internal override void InvalidateMirrorTransform() { // Do nothing becuase TopLevel should't apply MirrorTransform on himself. } From 808ada86cdaff999a2f5a62334c4947904e400d9 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 10:15:53 +0200 Subject: [PATCH 03/22] Make ContentControl.ContentChanged private again. Was added in #9803 for `TransitioningContentControl` but is no longer needed (and anyway it should be called `OnContentChanged` if we want to keep it). --- src/Avalonia.Controls/ContentControl.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/ContentControl.cs b/src/Avalonia.Controls/ContentControl.cs index f30920ed2e..0362f7ade4 100644 --- a/src/Avalonia.Controls/ContentControl.cs +++ b/src/Avalonia.Controls/ContentControl.cs @@ -116,19 +116,14 @@ namespace Avalonia.Controls return false; } - protected virtual void ContentChanged(AvaloniaPropertyChangedEventArgs e) + private void ContentChanged(AvaloniaPropertyChangedEventArgs e) { - UpdateLogicalTree(e.OldValue, e.NewValue); - } - - protected void UpdateLogicalTree(object? toRemove, object? toAdd) - { - if (toRemove is ILogical oldChild) + if (e.OldValue is ILogical oldChild) { LogicalChildren.Remove(oldChild); } - if (toAdd is ILogical newChild) + if (e.NewValue is ILogical newChild) { LogicalChildren.Add(newChild); } From d390b4796f4aa229a32287702dd616be8f0a1a41 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 11:05:09 +0200 Subject: [PATCH 04/22] Make IContentControl internal. Can probably be removed. --- src/Avalonia.Controls/IContentControl.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/IContentControl.cs b/src/Avalonia.Controls/IContentControl.cs index b2828c26e8..1f975d5fa6 100644 --- a/src/Avalonia.Controls/IContentControl.cs +++ b/src/Avalonia.Controls/IContentControl.cs @@ -8,8 +8,7 @@ namespace Avalonia.Controls /// Defines a control that displays according to a /// . /// - [NotClientImplementable] - public interface IContentControl + internal interface IContentControl { /// /// Gets or sets the content to display. From 6bbd56f7d979122c519a1425307db52e2aaed881 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 11:14:37 +0200 Subject: [PATCH 05/22] Make IHeadered internal. Can probably be removed. --- src/Avalonia.Controls/Avalonia.Controls.csproj | 2 ++ src/Avalonia.Controls/IHeadered.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 48761ca8b8..3f1753a4d3 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -14,6 +14,7 @@ + @@ -22,5 +23,6 @@ + diff --git a/src/Avalonia.Controls/IHeadered.cs b/src/Avalonia.Controls/IHeadered.cs index 8c1b5cfb1b..c59ddafe73 100644 --- a/src/Avalonia.Controls/IHeadered.cs +++ b/src/Avalonia.Controls/IHeadered.cs @@ -3,7 +3,7 @@ namespace Avalonia.Controls /// /// Defines a headered object. /// - public interface IHeadered + internal interface IHeadered { /// /// Gets or set the header. From 8f94a6505ba5667889719b698eaf5d8d32aaf803 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 11:36:36 +0200 Subject: [PATCH 06/22] Make IMenu, IMenuElement, IMenuItem internal. Should only be needed for unit tests. --- src/Avalonia.Controls/IMenu.cs | 3 +- src/Avalonia.Controls/IMenuElement.cs | 3 +- src/Avalonia.Controls/IMenuItem.cs | 3 +- .../Platform/DefaultMenuInteractionHandler.cs | 459 +++++++++--------- .../Platform/IMenuInteractionHandler.cs | 4 +- .../DefaultMenuInteractionHandlerTests.cs | 2 +- 6 files changed, 238 insertions(+), 236 deletions(-) diff --git a/src/Avalonia.Controls/IMenu.cs b/src/Avalonia.Controls/IMenu.cs index ddf2997014..b3ec77b108 100644 --- a/src/Avalonia.Controls/IMenu.cs +++ b/src/Avalonia.Controls/IMenu.cs @@ -8,8 +8,7 @@ namespace Avalonia.Controls /// /// Represents a or . /// - [NotClientImplementable] - public interface IMenu : IMenuElement, IInputElement + internal interface IMenu : IMenuElement, IInputElement { /// /// Gets the menu interaction handler. diff --git a/src/Avalonia.Controls/IMenuElement.cs b/src/Avalonia.Controls/IMenuElement.cs index 2a81d20bd9..a474f335f2 100644 --- a/src/Avalonia.Controls/IMenuElement.cs +++ b/src/Avalonia.Controls/IMenuElement.cs @@ -8,8 +8,7 @@ namespace Avalonia.Controls /// /// Represents an or . /// - [NotClientImplementable] - public interface IMenuElement : IInputElement, ILogical + internal interface IMenuElement : IInputElement, ILogical { /// /// Gets or sets the currently selected submenu item. diff --git a/src/Avalonia.Controls/IMenuItem.cs b/src/Avalonia.Controls/IMenuItem.cs index 1257d33684..3a9c5373a6 100644 --- a/src/Avalonia.Controls/IMenuItem.cs +++ b/src/Avalonia.Controls/IMenuItem.cs @@ -5,8 +5,7 @@ namespace Avalonia.Controls /// /// Represents a . /// - [NotClientImplementable] - public interface IMenuItem : IMenuElement + internal interface IMenuItem : IMenuElement { /// /// Gets or sets a value that indicates whether the item has a submenu. diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index d2b23a7ac3..79a3038edf 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -39,91 +39,20 @@ namespace Avalonia.Controls.Platform DelayRun = delayRun; } - public virtual void Attach(IMenu menu) - { - if (Menu != null) - { - throw new NotSupportedException("DefaultMenuInteractionHandler is already attached."); - } - - Menu = menu; - Menu.GotFocus += GotFocus; - Menu.LostFocus += LostFocus; - Menu.KeyDown += KeyDown; - Menu.PointerPressed += PointerPressed; - Menu.PointerReleased += PointerReleased; - Menu.AddHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed); - Menu.AddHandler(MenuBase.MenuOpenedEvent, MenuOpened); - Menu.AddHandler(MenuItem.PointerEnteredItemEvent, PointerEntered); - Menu.AddHandler(MenuItem.PointerExitedItemEvent, PointerExited); - Menu.AddHandler(InputElement.PointerMovedEvent, PointerMoved); - - _root = Menu.VisualRoot; - - if (_root is InputElement inputRoot) - { - inputRoot.AddHandler(InputElement.PointerPressedEvent, RootPointerPressed, RoutingStrategies.Tunnel); - } - - if (_root is WindowBase window) - { - window.Deactivated += WindowDeactivated; - } - - if (_root is TopLevel tl && tl.PlatformImpl is ITopLevelImpl pimpl) - pimpl.LostFocus += TopLevelLostPlatformFocus; - - _inputManagerSubscription = InputManager?.Process.Subscribe(RawInput); - } - - public virtual void Detach(IMenu menu) - { - if (Menu != menu) - { - throw new NotSupportedException("DefaultMenuInteractionHandler is not attached to the menu."); - } - - Menu.GotFocus -= GotFocus; - Menu.LostFocus -= LostFocus; - Menu.KeyDown -= KeyDown; - Menu.PointerPressed -= PointerPressed; - Menu.PointerReleased -= PointerReleased; - Menu.RemoveHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed); - Menu.RemoveHandler(MenuBase.MenuOpenedEvent, MenuOpened); - Menu.RemoveHandler(MenuItem.PointerEnteredItemEvent, PointerEntered); - Menu.RemoveHandler(MenuItem.PointerExitedItemEvent, PointerExited); - Menu.RemoveHandler(InputElement.PointerMovedEvent, PointerMoved); - - if (_root is InputElement inputRoot) - { - inputRoot.RemoveHandler(InputElement.PointerPressedEvent, RootPointerPressed); - } - - if (_root is WindowBase root) - { - root.Deactivated -= WindowDeactivated; - } - - if (_root is TopLevel tl && tl.PlatformImpl != null) - tl.PlatformImpl.LostFocus -= TopLevelLostPlatformFocus; - - _inputManagerSubscription?.Dispose(); - - Menu = null; - _root = null; - } + public void Attach(MenuBase menu) => AttachCore(menu); + public void Detach(MenuBase menu) => DetachCore(menu); protected Action DelayRun { get; } protected IInputManager? InputManager { get; } - protected IMenu? Menu { get; private set; } + internal IMenu? Menu { get; private set; } protected static TimeSpan MenuShowDelay { get; } = TimeSpan.FromMilliseconds(400); protected internal virtual void GotFocus(object? sender, GotFocusEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (item?.Parent != null) { @@ -133,7 +62,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void LostFocus(object? sender, RoutedEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (item != null) { @@ -143,146 +72,12 @@ namespace Avalonia.Controls.Platform protected internal virtual void KeyDown(object? sender, KeyEventArgs e) { - KeyDown(GetMenuItem(e.Source as Control), e); - } - - protected internal virtual void KeyDown(IMenuItem? item, KeyEventArgs e) - { - switch (e.Key) - { - case Key.Up: - case Key.Down: - { - if (item?.IsTopLevel == true && item.HasSubMenu) - { - if (!item.IsSubMenuOpen) - { - Open(item, true); - } - else - { - item.MoveSelection(NavigationDirection.First, true); - } - - e.Handled = true; - } - else - { - goto default; - } - break; - } - - case Key.Left: - { - if (item is { IsSubMenuOpen: true, SelectedItem: null }) - { - item.Close(); - } - else if (item?.Parent is IMenuItem { IsTopLevel: false, IsSubMenuOpen: true } parent) - { - parent.Close(); - parent.Focus(); - e.Handled = true; - } - else - { - goto default; - } - break; - } - - case Key.Right: - { - if (item != null && !item.IsTopLevel && item.HasSubMenu) - { - Open(item, true); - e.Handled = true; - } - else - { - goto default; - } - break; - } - - case Key.Enter: - { - if (item != null) - { - if (!item.HasSubMenu) - { - Click(item); - } - else - { - Open(item, true); - } - - e.Handled = true; - } - break; - } - - case Key.Escape: - { - if (item?.Parent is IMenuElement parent) - { - parent.Close(); - parent.Focus(); - } - else - { - Menu!.Close(); - } - - e.Handled = true; - break; - } - - default: - { - var direction = e.Key.ToNavigationDirection(); - - if (direction?.IsDirectional() == true) - { - if (item == null && _isContextMenu) - { - if (Menu!.MoveSelection(direction.Value, true) == true) - { - e.Handled = true; - } - } - else if (item?.Parent?.MoveSelection(direction.Value, true) == true) - { - // If the the parent is an IMenu which successfully moved its selection, - // and the current menu is open then close the current menu and open the - // new menu. - if (item.IsSubMenuOpen && - item.Parent is IMenu && - item.Parent.SelectedItem is object && - item.Parent.SelectedItem != item) - { - item.Close(); - Open(item.Parent.SelectedItem, true); - } - e.Handled = true; - } - } - - break; - } - } - - if (!e.Handled && item?.Parent is IMenuItem parentItem) - { - KeyDown(parentItem, e); - } + KeyDown(GetMenuItemCore(e.Source as Control), e); } protected internal virtual void AccessKeyPressed(object? sender, RoutedEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (item == null) { @@ -303,7 +98,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void PointerEntered(object? sender, RoutedEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (item?.Parent == null) { @@ -349,7 +144,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void PointerMoved(object? sender, PointerEventArgs e) { // HACK: #8179 needs to be addressed to correctly implement it in the PointerPressed method. - var item = GetMenuItem(e.Source as Control) as MenuItem; + var item = GetMenuItemCore(e.Source as Control) as MenuItem; if (item == null) return; @@ -370,7 +165,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void PointerExited(object? sender, RoutedEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (item?.Parent == null) { @@ -405,7 +200,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void PointerPressed(object? sender, PointerPressedEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (sender is Visual visual && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed && item?.HasSubMenu == true) @@ -436,7 +231,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void PointerReleased(object? sender, PointerReleasedEventArgs e) { - var item = GetMenuItem(e.Source as Control); + var item = GetMenuItemCore(e.Source as Control); if (e.InitialPressMouseButton == MouseButton.Left && item?.HasSubMenu == false) { @@ -478,13 +273,84 @@ namespace Avalonia.Controls.Platform { Menu?.Close(); } - - private void TopLevelLostPlatformFocus() + + internal static MenuItem? GetMenuItem(StyledElement? item) => (MenuItem?)GetMenuItemCore(item); + + internal void AttachCore(IMenu menu) { - Menu?.Close(); + if (Menu != null) + { + throw new NotSupportedException("DefaultMenuInteractionHandler is already attached."); + } + + Menu = menu; + Menu.GotFocus += GotFocus; + Menu.LostFocus += LostFocus; + Menu.KeyDown += KeyDown; + Menu.PointerPressed += PointerPressed; + Menu.PointerReleased += PointerReleased; + Menu.AddHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed); + Menu.AddHandler(MenuBase.MenuOpenedEvent, MenuOpened); + Menu.AddHandler(MenuItem.PointerEnteredItemEvent, PointerEntered); + Menu.AddHandler(MenuItem.PointerExitedItemEvent, PointerExited); + Menu.AddHandler(InputElement.PointerMovedEvent, PointerMoved); + + _root = Menu.VisualRoot; + + if (_root is InputElement inputRoot) + { + inputRoot.AddHandler(InputElement.PointerPressedEvent, RootPointerPressed, RoutingStrategies.Tunnel); + } + + if (_root is WindowBase window) + { + window.Deactivated += WindowDeactivated; + } + + if (_root is TopLevel tl && tl.PlatformImpl is ITopLevelImpl pimpl) + pimpl.LostFocus += TopLevelLostPlatformFocus; + + _inputManagerSubscription = InputManager?.Process.Subscribe(RawInput); } - protected void Click(IMenuItem item) + internal void DetachCore(IMenu menu) + { + if (Menu != menu) + { + throw new NotSupportedException("DefaultMenuInteractionHandler is not attached to the menu."); + } + + Menu.GotFocus -= GotFocus; + Menu.LostFocus -= LostFocus; + Menu.KeyDown -= KeyDown; + Menu.PointerPressed -= PointerPressed; + Menu.PointerReleased -= PointerReleased; + Menu.RemoveHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed); + Menu.RemoveHandler(MenuBase.MenuOpenedEvent, MenuOpened); + Menu.RemoveHandler(MenuItem.PointerEnteredItemEvent, PointerEntered); + Menu.RemoveHandler(MenuItem.PointerExitedItemEvent, PointerExited); + Menu.RemoveHandler(InputElement.PointerMovedEvent, PointerMoved); + + if (_root is InputElement inputRoot) + { + inputRoot.RemoveHandler(InputElement.PointerPressedEvent, RootPointerPressed); + } + + if (_root is WindowBase root) + { + root.Deactivated -= WindowDeactivated; + } + + if (_root is TopLevel tl && tl.PlatformImpl != null) + tl.PlatformImpl.LostFocus -= TopLevelLostPlatformFocus; + + _inputManagerSubscription?.Dispose(); + + Menu = null; + _root = null; + } + + internal void Click(IMenuItem item) { item.RaiseClick(); @@ -494,7 +360,7 @@ namespace Avalonia.Controls.Platform } } - protected void CloseMenu(IMenuItem item) + internal void CloseMenu(IMenuItem item) { var current = (IMenuElement?)item; @@ -506,7 +372,7 @@ namespace Avalonia.Controls.Platform current?.Close(); } - protected void CloseWithDelay(IMenuItem item) + internal void CloseWithDelay(IMenuItem item) { void Execute() { @@ -519,7 +385,141 @@ namespace Avalonia.Controls.Platform DelayRun(Execute, MenuShowDelay); } - protected void Open(IMenuItem item, bool selectFirst) + internal void KeyDown(IMenuItem? item, KeyEventArgs e) + { + switch (e.Key) + { + case Key.Up: + case Key.Down: + { + if (item?.IsTopLevel == true && item.HasSubMenu) + { + if (!item.IsSubMenuOpen) + { + Open(item, true); + } + else + { + item.MoveSelection(NavigationDirection.First, true); + } + + e.Handled = true; + } + else + { + goto default; + } + break; + } + + case Key.Left: + { + if (item is { IsSubMenuOpen: true, SelectedItem: null }) + { + item.Close(); + } + else if (item?.Parent is IMenuItem { IsTopLevel: false, IsSubMenuOpen: true } parent) + { + parent.Close(); + parent.Focus(); + e.Handled = true; + } + else + { + goto default; + } + break; + } + + case Key.Right: + { + if (item != null && !item.IsTopLevel && item.HasSubMenu) + { + Open(item, true); + e.Handled = true; + } + else + { + goto default; + } + break; + } + + case Key.Enter: + { + if (item != null) + { + if (!item.HasSubMenu) + { + Click(item); + } + else + { + Open(item, true); + } + + e.Handled = true; + } + break; + } + + case Key.Escape: + { + if (item?.Parent is IMenuElement parent) + { + parent.Close(); + parent.Focus(); + } + else + { + Menu!.Close(); + } + + e.Handled = true; + break; + } + + default: + { + var direction = e.Key.ToNavigationDirection(); + + if (direction?.IsDirectional() == true) + { + if (item == null && _isContextMenu) + { + if (Menu!.MoveSelection(direction.Value, true) == true) + { + e.Handled = true; + } + } + else if (item?.Parent?.MoveSelection(direction.Value, true) == true) + { + // If the the parent is an IMenu which successfully moved its selection, + // and the current menu is open then close the current menu and open the + // new menu. + if (item.IsSubMenuOpen && + item.Parent is IMenu && + item.Parent.SelectedItem is object && + item.Parent.SelectedItem != item) + { + item.Close(); + Open(item.Parent.SelectedItem, true); + } + e.Handled = true; + } + } + + break; + } + } + + if (!e.Handled && item?.Parent is IMenuItem parentItem) + { + KeyDown(parentItem, e); + } + } + + internal void Open(IMenuItem item, bool selectFirst) { item.Open(); @@ -529,7 +529,7 @@ namespace Avalonia.Controls.Platform } } - protected void OpenWithDelay(IMenuItem item) + internal void OpenWithDelay(IMenuItem item) { void Execute() { @@ -542,7 +542,7 @@ namespace Avalonia.Controls.Platform DelayRun(Execute, MenuShowDelay); } - protected void SelectItemAndAncestors(IMenuItem item) + internal void SelectItemAndAncestors(IMenuItem item) { var current = (IMenuItem?)item; @@ -553,7 +553,7 @@ namespace Avalonia.Controls.Platform } } - protected static IMenuItem? GetMenuItem(StyledElement? item) + internal static IMenuItem? GetMenuItemCore(StyledElement? item) { while (true) { @@ -565,6 +565,11 @@ namespace Avalonia.Controls.Platform } } + private void TopLevelLostPlatformFocus() + { + Menu?.Close(); + } + private static void DefaultDelayRun(Action action, TimeSpan timeSpan) { DispatcherTimer.RunOnce(action, timeSpan); diff --git a/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs index 47b5a048b0..d1d2267f05 100644 --- a/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs @@ -12,11 +12,11 @@ namespace Avalonia.Controls.Platform /// Attaches the interaction handler to a menu. /// /// The menu. - void Attach(IMenu menu); + void Attach(MenuBase menu); /// /// Detaches the interaction handler from the attached menu. /// - void Detach(IMenu menu); + void Detach(MenuBase menu); } } diff --git a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs index eaf95b0c8c..506a62525c 100644 --- a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs @@ -554,7 +554,7 @@ namespace Avalonia.Controls.UnitTests.Platform var contextMenu = Mock.Of(x => x.MoveSelection(NavigationDirection.Down, true) == true); var e = new KeyEventArgs { Key = Key.Down, Source = contextMenu }; - target.Attach(contextMenu); + target.AttachCore(contextMenu); target.KeyDown(contextMenu, e); Mock.Get(contextMenu).Verify(x => x.MoveSelection(NavigationDirection.Down, true)); From 8428ea9d6b0e44b1dc3f27aa4cd95f97a5b486dc Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 11:51:22 +0200 Subject: [PATCH 07/22] Make IMainMenu and IAccessKeyHandler internal. --- src/Avalonia.Base/Input/IAccessKeyHandler.cs | 3 +-- src/Avalonia.Base/Input/IInputRoot.cs | 5 ----- src/Avalonia.Base/Input/IMainMenu.cs | 5 +---- src/Avalonia.Controls/Menu.cs | 2 +- src/Avalonia.Controls/MenuItemAccessKeyHandler.cs | 2 +- src/Avalonia.Controls/Primitives/AccessText.cs | 2 +- src/Avalonia.Controls/TopLevel.cs | 2 +- tests/Avalonia.UnitTests/TestRoot.cs | 2 -- 8 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Base/Input/IAccessKeyHandler.cs b/src/Avalonia.Base/Input/IAccessKeyHandler.cs index 93a50968e2..aaad93eb23 100644 --- a/src/Avalonia.Base/Input/IAccessKeyHandler.cs +++ b/src/Avalonia.Base/Input/IAccessKeyHandler.cs @@ -5,8 +5,7 @@ namespace Avalonia.Input /// /// Defines the interface for classes that handle access keys for a window. /// - [Unstable] - public interface IAccessKeyHandler + internal interface IAccessKeyHandler { /// /// Gets or sets the window's main menu. diff --git a/src/Avalonia.Base/Input/IInputRoot.cs b/src/Avalonia.Base/Input/IInputRoot.cs index 0100b22ba7..d0921eea2d 100644 --- a/src/Avalonia.Base/Input/IInputRoot.cs +++ b/src/Avalonia.Base/Input/IInputRoot.cs @@ -8,11 +8,6 @@ namespace Avalonia.Input [NotClientImplementable] public interface IInputRoot : IInputElement { - /// - /// Gets or sets the access key handler. - /// - IAccessKeyHandler AccessKeyHandler { get; } - /// /// Gets or sets the keyboard navigation handler. /// diff --git a/src/Avalonia.Base/Input/IMainMenu.cs b/src/Avalonia.Base/Input/IMainMenu.cs index 0010397c1a..cc1b88d4c3 100644 --- a/src/Avalonia.Base/Input/IMainMenu.cs +++ b/src/Avalonia.Base/Input/IMainMenu.cs @@ -1,15 +1,12 @@ using System; using Avalonia.Interactivity; -using Avalonia.Metadata; -using Avalonia.VisualTree; namespace Avalonia.Input { /// /// Defines the interface for a window's main menu. /// - [NotClientImplementable] - public interface IMainMenu + internal interface IMainMenu { /// /// Gets a value indicating whether the menu is open. diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs index 4df423dee8..fe4d42c603 100644 --- a/src/Avalonia.Controls/Menu.cs +++ b/src/Avalonia.Controls/Menu.cs @@ -87,7 +87,7 @@ namespace Avalonia.Controls { base.OnAttachedToVisualTree(e); - var inputRoot = e.Root as IInputRoot; + var inputRoot = e.Root as TopLevel; if (inputRoot?.AccessKeyHandler != null) { diff --git a/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs b/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs index 381f1799d4..e1e7779f17 100644 --- a/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs +++ b/src/Avalonia.Controls/MenuItemAccessKeyHandler.cs @@ -9,7 +9,7 @@ namespace Avalonia.Controls /// /// Handles access keys within a /// - public class MenuItemAccessKeyHandler : IAccessKeyHandler + internal class MenuItemAccessKeyHandler : IAccessKeyHandler { /// /// The registered access keys. diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs index c5dbc3000f..2e570e25c7 100644 --- a/src/Avalonia.Controls/Primitives/AccessText.cs +++ b/src/Avalonia.Controls/Primitives/AccessText.cs @@ -86,7 +86,7 @@ namespace Avalonia.Controls.Primitives protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); - _accessKeys = (e.Root as IInputRoot)?.AccessKeyHandler; + _accessKeys = (e.Root as TopLevel)?.AccessKeyHandler; if (_accessKeys != null && AccessKey != 0) { diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index f655016769..474735d25b 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -386,7 +386,7 @@ namespace Avalonia.Controls /// /// Gets the access key handler for the window. /// - IAccessKeyHandler IInputRoot.AccessKeyHandler => _accessKeyHandler!; + internal IAccessKeyHandler AccessKeyHandler => _accessKeyHandler!; /// /// Gets or sets the keyboard navigation handler for the window. diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs index 8dabfe2197..80f0cf5406 100644 --- a/tests/Avalonia.UnitTests/TestRoot.cs +++ b/tests/Avalonia.UnitTests/TestRoot.cs @@ -51,8 +51,6 @@ namespace Avalonia.UnitTests public IRenderer Renderer { get; set; } - public IAccessKeyHandler AccessKeyHandler => null; - public IKeyboardNavigationHandler KeyboardNavigationHandler => null; public IFocusManager FocusManager => AvaloniaLocator.Current.GetService(); From da2af10efe1b47e5ce743b720d78c66373535c9e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 11:53:23 +0200 Subject: [PATCH 08/22] Make INativeMenuExporterEventsImplBridge a private API. --- src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs index 29963e4821..6a22676a69 100644 --- a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs +++ b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs @@ -2,7 +2,7 @@ using Avalonia.Metadata; namespace Avalonia.Controls { - [Unstable] + [PrivateApi] public interface INativeMenuExporterEventsImplBridge { void RaiseNeedsUpdate (); From d992fc2b4f011429fcb9947a700089bc246a4e75 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 12:49:06 +0200 Subject: [PATCH 09/22] Hide IChildIndexProvider interface method. --- src/Avalonia.Controls/Panel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Panel.cs b/src/Avalonia.Controls/Panel.cs index eff6603727..4705b0e9a5 100644 --- a/src/Avalonia.Controls/Panel.cs +++ b/src/Avalonia.Controls/Panel.cs @@ -213,7 +213,7 @@ namespace Avalonia.Controls } /// - public bool TryGetTotalCount(out int count) + bool IChildIndexProvider.TryGetTotalCount(out int count) { count = Children.Count; return true; From 61be135c8cbb5fe11ebf6484ed6e2e77ef27b421 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 12:52:30 +0200 Subject: [PATCH 10/22] Don't expose protected fields. --- .../ColorSlider/ColorSlider.cs | 6 ++-- src/Avalonia.Controls/Slider.cs | 28 ++++++++++++++++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs index a6d9ca459f..31ac18100e 100644 --- a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs +++ b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs @@ -98,10 +98,10 @@ namespace Avalonia.Controls.Primitives int pixelWidth; int pixelHeight; - if (base._track != null) + if (base.Track != null) { - pixelWidth = Convert.ToInt32(base._track.Bounds.Width * scale); - pixelHeight = Convert.ToInt32(base._track.Bounds.Height * scale); + pixelWidth = Convert.ToInt32(base.Track.Bounds.Width * scale); + pixelHeight = Convert.ToInt32(base.Track.Bounds.Height * scale); } else { diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs index b0dff5be79..de3c4023bd 100644 --- a/src/Avalonia.Controls/Slider.cs +++ b/src/Avalonia.Controls/Slider.cs @@ -86,10 +86,10 @@ namespace Avalonia.Controls TickBar.TicksProperty.AddOwner(); // Slider required parts - protected bool _isDragging; - protected Track? _track; - protected Button? _decreaseButton; - protected Button? _increaseButton; + private bool _isDragging; + private Track? _track; + private Button? _decreaseButton; + private Button? _increaseButton; private IDisposable? _decreaseButtonPressDispose; private IDisposable? _decreaseButtonReleaseDispose; private IDisposable? _increaseButtonSubscription; @@ -181,6 +181,26 @@ namespace Avalonia.Controls set { SetValue(TickPlacementProperty, value); } } + /// + /// Gets a value indicating whether the is currently being dragged. + /// + protected bool IsDragging => _isDragging; + + /// + /// Gets the part of the . + /// + protected Track? Track => _track; + + /// + /// Gets the that decreases the value. + /// + protected Button? DecreaseButton => _decreaseButton; + + /// + /// Gets the that increases the value. + /// + protected Button? IncreaseButton => _increaseButton; + /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { From 16615a43d3fff2b27977cdb598c111443e3c563d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 12:59:37 +0200 Subject: [PATCH 11/22] Don't expose pseudoclass constants. 1. They don't follow naming conventions 2. If we're going to expose them, why just `protected`? 3. If we do it, we should do it on all controls --- src/Avalonia.Controls/Button.cs | 4 ++-- .../CalendarDatePicker/CalendarDatePicker.cs | 4 ++-- src/Avalonia.Controls/ComboBox.cs | 5 +++-- .../SplitButton/SplitButton.cs | 6 +++--- src/Avalonia.Controls/SplitView/SplitView.cs | 18 +++++++++--------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index f48d7a7cc1..d8c31fc477 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -34,8 +34,8 @@ namespace Avalonia.Controls [PseudoClasses(pcFlyoutOpen, pcPressed)] public class Button : ContentControl, ICommandSource, IClickableControl { - protected const string pcPressed = ":pressed"; - protected const string pcFlyoutOpen = ":flyout-open"; + private const string pcPressed = ":pressed"; + private const string pcFlyoutOpen = ":flyout-open"; /// /// Defines the property. diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs index 90153d3293..679ac4a853 100644 --- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs @@ -26,8 +26,8 @@ namespace Avalonia.Controls [PseudoClasses(pcFlyoutOpen, pcPressed)] public partial class CalendarDatePicker : TemplatedControl { - protected const string pcPressed = ":pressed"; - protected const string pcFlyoutOpen = ":flyout-open"; + private const string pcPressed = ":pressed"; + private const string pcFlyoutOpen = ":flyout-open"; private const string ElementTextBox = "PART_TextBox"; private const string ElementButton = "PART_Button"; diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 8872afab9f..926cd5d58e 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -21,8 +21,9 @@ namespace Avalonia.Controls [PseudoClasses(pcDropdownOpen, pcPressed)] public class ComboBox : SelectingItemsControl { - public const string pcDropdownOpen = ":dropdownopen"; - public const string pcPressed = ":pressed"; + internal const string pcDropdownOpen = ":dropdownopen"; + internal const string pcPressed = ":pressed"; + /// /// The default value for the property. /// diff --git a/src/Avalonia.Controls/SplitButton/SplitButton.cs b/src/Avalonia.Controls/SplitButton/SplitButton.cs index 7f10c632c5..bc46e549eb 100644 --- a/src/Avalonia.Controls/SplitButton/SplitButton.cs +++ b/src/Avalonia.Controls/SplitButton/SplitButton.cs @@ -18,9 +18,9 @@ namespace Avalonia.Controls [PseudoClasses(pcFlyoutOpen, pcPressed)] public class SplitButton : ContentControl, ICommandSource { - protected const string pcChecked = ":checked"; - protected const string pcPressed = ":pressed"; - protected const string pcFlyoutOpen = ":flyout-open"; + internal const string pcChecked = ":checked"; + internal const string pcPressed = ":pressed"; + internal const string pcFlyoutOpen = ":flyout-open"; /// /// Raised when the user presses the primary part of the . diff --git a/src/Avalonia.Controls/SplitView/SplitView.cs b/src/Avalonia.Controls/SplitView/SplitView.cs index 3ad656ee3c..b943a01a4b 100644 --- a/src/Avalonia.Controls/SplitView/SplitView.cs +++ b/src/Avalonia.Controls/SplitView/SplitView.cs @@ -22,15 +22,15 @@ namespace Avalonia.Controls [PseudoClasses(pcLightDismiss)] public class SplitView : ContentControl { - protected const string pcOpen = ":open"; - protected const string pcClosed = ":closed"; - protected const string pcCompactOverlay = ":compactoverlay"; - protected const string pcCompactInline = ":compactinline"; - protected const string pcOverlay = ":overlay"; - protected const string pcInline = ":inline"; - protected const string pcLeft = ":left"; - protected const string pcRight = ":right"; - protected const string pcLightDismiss = ":lightDismiss"; + private const string pcOpen = ":open"; + private const string pcClosed = ":closed"; + private const string pcCompactOverlay = ":compactoverlay"; + private const string pcCompactInline = ":compactinline"; + private const string pcOverlay = ":overlay"; + private const string pcInline = ":inline"; + private const string pcLeft = ":left"; + private const string pcRight = ":right"; + private const string pcLightDismiss = ":lightDismiss"; /// /// Defines the property From de0ebdda22ee2e520100ca2a33bb36a911f666ce Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:02:13 +0200 Subject: [PATCH 12/22] Don't expose fields. --- src/Avalonia.Controls/TextBlock.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index c1edf23c89..11a180c4d7 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -144,8 +144,8 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect( nameof(Inlines), t => t.Inlines, (t, v) => t.Inlines = v); - protected TextLayout? _textLayout; - protected Size _constraint; + private TextLayout? _textLayout; + private Size _constraint; private IReadOnlyList? _textRuns; private InlineCollection? _inlines; From b0bcfcfbf7591c87de03b0494dc5166653e19e36 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:04:00 +0200 Subject: [PATCH 13/22] Make TextBlock.SimpleTextSource private. --- src/Avalonia.Controls/TextBlock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index 11a180c4d7..6144136882 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -829,7 +829,7 @@ namespace Avalonia.Controls InvalidateTextLayout(); } - protected readonly record struct SimpleTextSource : ITextSource + private readonly record struct SimpleTextSource : ITextSource { private readonly string _text; private readonly TextRunProperties _defaultProperties; From 224187331649f72e035079872c5731fcd1889077 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:05:30 +0200 Subject: [PATCH 14/22] Make TextBox.RemoveInvalidCharacters private. --- src/Avalonia.Controls/TextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 2a8fdd30c7..51a7fe9b7f 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -1017,7 +1017,7 @@ namespace Avalonia.Controls } } - public string? RemoveInvalidCharacters(string? text) + private string? RemoveInvalidCharacters(string? text) { if (text is null) return null; From 4ea25f7990aefe26faea37a2fcbd15808071e8f1 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:10:19 +0200 Subject: [PATCH 15/22] Make ToggleSwitch.UpdateKnobPos private. --- src/Avalonia.Controls/ToggleSwitch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ToggleSwitch.cs b/src/Avalonia.Controls/ToggleSwitch.cs index 108deba257..29e1b90ca0 100644 --- a/src/Avalonia.Controls/ToggleSwitch.cs +++ b/src/Avalonia.Controls/ToggleSwitch.cs @@ -241,7 +241,7 @@ namespace Avalonia.Controls } } - protected void UpdateKnobPos(bool value) + private void UpdateKnobPos(bool value) { if ((_switchKnob != null) && (_knobsPanel != null)) { From 673b3e4b710aea58dc7957ec9735effe0d956069 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:15:33 +0200 Subject: [PATCH 16/22] Make top level Handle* methods internal. --- src/Avalonia.Controls/TopLevel.cs | 8 ++++---- src/Avalonia.Controls/Window.cs | 4 ++-- src/Avalonia.Controls/WindowBase.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 474735d25b..4736398509 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -529,7 +529,7 @@ namespace Avalonia.Controls /// Handles a paint notification from . /// /// The dirty area. - protected virtual void HandlePaint(Rect rect) + private void HandlePaint(Rect rect) { Renderer.Paint(rect); } @@ -537,7 +537,7 @@ namespace Avalonia.Controls /// /// Handles a closed notification from . /// - protected virtual void HandleClosed() + private protected virtual void HandleClosed() { Renderer.SceneInvalidated -= SceneInvalidated; // We need to wait for the renderer to complete any in-flight operations @@ -595,7 +595,7 @@ namespace Avalonia.Controls /// . /// /// The window scaling. - protected virtual void HandleScalingChanged(double scaling) + private void HandleScalingChanged(double scaling) { LayoutHelper.InvalidateSelfAndChildrenMeasure(this); ScalingChanged?.Invoke(this, EventArgs.Empty); @@ -615,7 +615,7 @@ namespace Avalonia.Controls return false; } - protected virtual void HandleTransparencyLevelChanged(WindowTransparencyLevel transparencyLevel) + private void HandleTransparencyLevelChanged(WindowTransparencyLevel transparencyLevel) { if(_transparencyFallbackBorder != null) { diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 3f04350995..e64341b735 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -535,7 +535,7 @@ namespace Avalonia.Controls return true; } - protected virtual void HandleWindowStateChanged(WindowState state) + private void HandleWindowStateChanged(WindowState state) { WindowState = state; @@ -979,7 +979,7 @@ namespace Avalonia.Controls return ClientSize; } - protected sealed override void HandleClosed() + private protected sealed override void HandleClosed() { RaiseEvent(new RoutedEventArgs(WindowClosedEvent)); diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index b19ad49820..491c32887c 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -226,7 +226,7 @@ namespace Avalonia.Controls /// An that contains the event data. protected virtual void OnResized(WindowResizedEventArgs e) => Resized?.Invoke(this, e); - protected override void HandleClosed() + private protected override void HandleClosed() { using (FreezeVisibilityChangeHandling()) { From e4634a917eb126f483c525a7c7fe5bbd679ceb82 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:24:13 +0200 Subject: [PATCH 17/22] Make TopLevel.CreateLayoutManager internal. Should only be needed for unit tests. --- src/Avalonia.Controls/TopLevel.cs | 2 +- tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs | 2 +- tests/Avalonia.Controls.UnitTests/TextBoxTests.cs | 2 +- tests/Avalonia.Controls.UnitTests/TopLevelTests.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 4736398509..3a206c0e15 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -523,7 +523,7 @@ namespace Avalonia.Controls /// /// Creates the layout manager for this . /// - protected virtual ILayoutManager CreateLayoutManager() => new LayoutManager(this); + private protected virtual ILayoutManager CreateLayoutManager() => new LayoutManager(this); /// /// Handles a paint notification from . diff --git a/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs index 04acd1c36d..dead810dbb 100644 --- a/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs @@ -1004,7 +1004,7 @@ namespace Avalonia.Controls.UnitTests _layoutManager = layoutManager ?? new LayoutManager(this); } - protected override ILayoutManager CreateLayoutManager() => _layoutManager; + private protected override ILayoutManager CreateLayoutManager() => _layoutManager; } private static Mock CreateMockTopLevelImpl() diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index ca1986d293..0d559557fe 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -1208,7 +1208,7 @@ namespace Avalonia.Controls.UnitTests _layoutManager = layoutManager ?? new LayoutManager(this); } - protected override ILayoutManager CreateLayoutManager() => _layoutManager; + private protected override ILayoutManager CreateLayoutManager() => _layoutManager; } private static Mock CreateMockTopLevelImpl() diff --git a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs index 0884dd306a..1c7935e167 100644 --- a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs @@ -339,7 +339,7 @@ namespace Avalonia.Controls.UnitTests _layoutManager = layoutManager ?? new LayoutManager(this); } - protected override ILayoutManager CreateLayoutManager() => _layoutManager; + private protected override ILayoutManager CreateLayoutManager() => _layoutManager; } } } From f6699faf4a20307eea8ff2d5ee557f2c4b02e0bf Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:24:25 +0200 Subject: [PATCH 18/22] Make FreezeVisibilityChangeHandling internal. --- src/Avalonia.Controls/WindowBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 491c32887c..6e0c6313f1 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -60,7 +60,7 @@ namespace Avalonia.Controls impl.PositionChanged = HandlePositionChanged; } - protected IDisposable FreezeVisibilityChangeHandling() + private protected IDisposable FreezeVisibilityChangeHandling() { return new IgnoreVisibilityChangesDisposable(this); } From 4c194b47c22070e913f7382a66c227010ebb8b50 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:37:22 +0200 Subject: [PATCH 19/22] Removed ContentPresenter.CreateChild. Unused API and I'm not sure we want to expose an extension point here. --- src/Avalonia.Controls/Presenters/ContentPresenter.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index 736c338c10..972fd2d4ff 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -540,17 +540,6 @@ namespace Avalonia.Controls.Presenters BoxShadow); } - /// - /// Creates the child control. - /// - /// The child control or null. - protected virtual Control? CreateChild() - { - var content = Content; - var oldChild = Child; - return CreateChild(content, oldChild, ContentTemplate); - } - private Control? CreateChild(object? content, Control? oldChild, IDataTemplate? template) { var newChild = content as Control; From 38a77e2f6966a575b80d2b5ca345e665a3fd083d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:39:59 +0200 Subject: [PATCH 20/22] Make IContentPresenterHost internal. Can probably be removed? --- src/Avalonia.Controls/Presenters/IContentPresenterHost.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs b/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs index 4c1e16ef72..dd1aafba65 100644 --- a/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs +++ b/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs @@ -1,7 +1,5 @@ using Avalonia.Collections; using Avalonia.LogicalTree; -using Avalonia.Metadata; -using Avalonia.Styling; namespace Avalonia.Controls.Presenters { @@ -16,8 +14,7 @@ namespace Avalonia.Controls.Presenters /// parent control's template is instantiated so they register themselves using this /// interface. /// - [NotClientImplementable] - public interface IContentPresenterHost + internal interface IContentPresenterHost { /// /// Gets a collection describing the logical children of the host control. From 79b043cbfabb153a30d4d42dbb5b8a8915b7add4 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 13:55:30 +0200 Subject: [PATCH 21/22] Remove ExportAvaloniaModuleAttribute . This feature is no longer supported. --- .../Platform/ExportAvaloniaModuleAttribute.cs | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/Avalonia.Controls/Platform/ExportAvaloniaModuleAttribute.cs diff --git a/src/Avalonia.Controls/Platform/ExportAvaloniaModuleAttribute.cs b/src/Avalonia.Controls/Platform/ExportAvaloniaModuleAttribute.cs deleted file mode 100644 index f271abb59a..0000000000 --- a/src/Avalonia.Controls/Platform/ExportAvaloniaModuleAttribute.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -namespace Avalonia.Platform -{ - /// - /// Defines an "Avalonia Module", a 3rd party extension to Avalonia that can be automatically initialized by an AppBuilder instance. - /// - /// - /// Avalonia Modules can either be platform independent (ex default control styles provider) or dependent on a - /// specific windowing or rendering subsystem being used (ex native rendering speedup, subsystem-specific interop backends). - /// In the case of a subsystem-specific module, you can specify multiple module implementations, and also a fallback - /// platform-independent module if you so choose. Additionally, these different implementations can be in different assemblies. - /// They just need to all share the same module name. - /// - /// For example, if I had a module Foo that has a special back-end for Skia and a less performant/less user friendly back-end for - /// any other rendering subsystem, I would do the following: - /// - /// // In assembly FooModuleSkia.dll - /// [assembly:ExportAvaloniaModule("Foo", typeof(FooModuleSkia), ForRenderingSubsystem="Skia")] - /// - /// class FooModuleSkia - /// { - /// public FooModuleSkia() - /// { - /// InitializeModule(); - /// } - /// } - /// - /// // In assembly FooModuleFallback.dll - /// [assembly:ExportAvaloniaModule("Foo", typeof(FooModuleFallback))] - /// - /// class FooModuleFallback - /// { - /// public FooModuleFallback() - /// { - /// InitializeModule(); - /// } - /// } - /// - /// - /// The fallback module will only be initialized if the Skia-specific module is not applicable. - /// - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class ExportAvaloniaModuleAttribute : Attribute - { - public ExportAvaloniaModuleAttribute(string name, Type moduleType) - { - Name = name; - ModuleType = moduleType; - } - - public string Name { get; private set; } - public Type ModuleType { get; private set; } - - public string ForWindowingSubsystem { get; set; } = ""; - public string ForRenderingSubsystem { get; set; } = ""; - } -} From a99839be1d1a481175731ba384398d533e64ca16 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 22 May 2023 22:44:00 +0200 Subject: [PATCH 22/22] Remove unneeded protected properties. --- src/Avalonia.Controls/Slider.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs index de3c4023bd..25fff93f85 100644 --- a/src/Avalonia.Controls/Slider.cs +++ b/src/Avalonia.Controls/Slider.cs @@ -191,16 +191,6 @@ namespace Avalonia.Controls /// protected Track? Track => _track; - /// - /// Gets the that decreases the value. - /// - protected Button? DecreaseButton => _decreaseButton; - - /// - /// Gets the that increases the value. - /// - protected Button? IncreaseButton => _increaseButton; - /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) {