From 282071751d9ebfdbf66c3be61851f23e54fae8dc Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 19 Aug 2022 18:05:42 +0200 Subject: [PATCH 01/12] fix: CS0169 Never used field --- src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs | 1 - src/Avalonia.X11/NativeDialogs/Gtk.cs | 3 --- .../Avalonia.LinuxFramebuffer/Input/EvDev/EvDevBackend.cs | 1 - 3 files changed, 5 deletions(-) diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index dc2b2cd7cc..79cf909e55 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -129,7 +129,6 @@ namespace Avalonia.Controls private bool _clipValueToMinMax; private bool _isSyncingTextAndValueProperties; private bool _isTextChangedFromUI; - private CultureInfo? _cultureInfo; private NumberStyles _parsingNumberStyle = NumberStyles.Any; private NumberFormatInfo? _numberFormat; diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs index ae04c072a5..d5eae037a9 100644 --- a/src/Avalonia.X11/NativeDialogs/Gtk.cs +++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs @@ -258,9 +258,6 @@ namespace Avalonia.X11.NativeDialogs public static IntPtr GetForeignWindow(IntPtr xid) => gdk_x11_window_foreign_new_for_display(s_display, xid); - static object s_startGtkLock = new(); - static Task s_startGtkTask; - public static Task StartGtk() { return StartGtkCore(); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/EvDev/EvDevBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/EvDev/EvDevBackend.cs index 2eb10ae666..1e3c4bed48 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/EvDev/EvDevBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/EvDev/EvDevBackend.cs @@ -13,7 +13,6 @@ namespace Avalonia.LinuxFramebuffer.Input.EvDev private readonly EvDevDeviceDescription[] _deviceDescriptions; private readonly List _handlers = new List(); private int _epoll; - private bool _isQueueHandlerTriggered; private object _lock = new object(); private Action _onInput; private IInputRoot _inputRoot; From 404bb8745ee834d11d5a30cada7428c78d810bab Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 19 Aug 2022 18:09:41 +0200 Subject: [PATCH 02/12] fix: Warning CS0168 The variable 'e' is declared but never used --- tests/Avalonia.IntegrationTests.Appium/WindowTests.cs | 2 +- tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs b/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs index 382306ac83..9cce169744 100644 --- a/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs +++ b/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs @@ -230,7 +230,7 @@ namespace Avalonia.IntegrationTests.Appium PixelRect.Parse(_session.FindElementByAccessibilityId("ScreenRect").Text), double.Parse(_session.FindElementByAccessibilityId("Scaling").Text)); } - catch (OpenQA.Selenium.NoSuchElementException e) when (retry++ < 3) + catch (OpenQA.Selenium.NoSuchElementException) when (retry++ < 3) { // MacOS sometimes seems to need a bit of time to get itself back in order after switching out // of fullscreen. diff --git a/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs b/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs index 4e5344dd25..facb25c18e 100644 --- a/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs +++ b/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs @@ -30,7 +30,7 @@ namespace Avalonia.IntegrationTests.Appium tab.Click(); return; } - catch (WebDriverException e) when (retry++ < 3) + catch (WebDriverException) when (retry++ < 3) { // MacOS sometimes seems to need a bit of time to get itself back in order after switching out // of fullscreen. From fab2fe7aa0dcc4c36bc6d9a2a2b0895015d20d63 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 19 Aug 2022 18:12:44 +0200 Subject: [PATCH 03/12] fix: Warning CS0414 The field is assigned but its value is never used --- src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs | 3 --- src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index 07db6013c7..338a3420fa 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -42,7 +42,6 @@ namespace Avalonia.Web.Blazor private GRGlInterface? _glInterface; private const SKColorType ColorType = SKColorType.Rgba8888; - private bool _initialised; private bool _useGL; private bool _inputElementFocused; @@ -300,8 +299,6 @@ namespace Avalonia.Web.Blazor _interop.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi)); - _initialised = true; - Threading.Dispatcher.UIThread.Post(async () => { _interop.RequestAnimationFrame(true); diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs index 3adefd965f..92e2b0689e 100644 --- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs +++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs @@ -17,7 +17,6 @@ namespace Avalonia.Win32.Input private bool _active; private bool _showCompositionWindow; private Imm32CaretManager _caretManager = new(); - private bool _showCandidateList; private ushort _langId; private const int _caretMargin = 1; @@ -32,7 +31,6 @@ namespace Avalonia.Win32.Input _active = false; _langId = PRIMARYLANGID(LGID(HKL)); _showCompositionWindow = true; - _showCandidateList = true; IsComposing = false; } @@ -50,7 +48,6 @@ namespace Avalonia.Win32.Input _active = false; _langId = 0; _showCompositionWindow = false; - _showCandidateList = false; IsComposing = false; } From 0cc0443d34567f0d20082eaee29625a732b93849 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 1 Sep 2022 22:33:03 +0200 Subject: [PATCH 04/12] Display window order in integration test app. The previous method of relying on the order of windows returned by appium to determine window z-order proved not to be reliable. Instead use p/invoke to read `NSWindow.orderedIndex` on a timer and display it in a text box in the `ShowWindowtest` window. This commit doesn't update the tests to use this new info though. --- .../IntegrationTestApp/MacOSIntegration.cs | 27 ++++++++++++++++++ .../IntegrationTestApp/ShowWindowTest.axaml | 8 ++++-- .../ShowWindowTest.axaml.cs | 28 +++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 samples/IntegrationTestApp/MacOSIntegration.cs diff --git a/samples/IntegrationTestApp/MacOSIntegration.cs b/samples/IntegrationTestApp/MacOSIntegration.cs new file mode 100644 index 0000000000..f700a5b4e2 --- /dev/null +++ b/samples/IntegrationTestApp/MacOSIntegration.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; +using Avalonia.Controls; + +namespace IntegrationTestApp +{ + public static class MacOSIntegration + { + [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "sel_registerName")] + private static extern IntPtr GetHandle(string name); + + [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")] + private static extern long Int64_objc_msgSend(IntPtr receiver, IntPtr selector); + + private static readonly IntPtr s_orderedIndexSelector; + + static MacOSIntegration() + { + s_orderedIndexSelector = GetHandle("orderedIndex");; + } + + public static long GetOrderedIndex(Window window) + { + return Int64_objc_msgSend(window.PlatformImpl!.Handle.Handle, s_orderedIndexSelector); + } + } +} diff --git a/samples/IntegrationTestApp/ShowWindowTest.axaml b/samples/IntegrationTestApp/ShowWindowTest.axaml index 4001bac7e2..17c359df51 100644 --- a/samples/IntegrationTestApp/ShowWindowTest.axaml +++ b/samples/IntegrationTestApp/ShowWindowTest.axaml @@ -3,7 +3,7 @@ x:Class="IntegrationTestApp.ShowWindowTest" Name="SecondaryWindow" Title="Show Window Test"> - + @@ -31,6 +31,10 @@ Maximized Fullscreen - + + + + + diff --git a/samples/IntegrationTestApp/ShowWindowTest.axaml.cs b/samples/IntegrationTestApp/ShowWindowTest.axaml.cs index 001f186761..43875dd990 100644 --- a/samples/IntegrationTestApp/ShowWindowTest.axaml.cs +++ b/samples/IntegrationTestApp/ShowWindowTest.axaml.cs @@ -1,21 +1,32 @@ using System; +using System.Runtime.InteropServices; using Avalonia; using Avalonia.Controls; -using Avalonia.Interactivity; using Avalonia.Markup.Xaml; -using Avalonia.Rendering; +using Avalonia.Threading; namespace IntegrationTestApp { public class ShowWindowTest : Window { + private readonly DispatcherTimer? _timer; + private readonly TextBox? _orderTextBox; + public ShowWindowTest() { InitializeComponent(); DataContext = this; PositionChanged += (s, e) => this.GetControl("Position").Text = $"{Position}"; - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + _orderTextBox = this.GetControl("Order"); + _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) }; + _timer.Tick += TimerOnTick; + _timer.Start(); + } + } + private void InitializeComponent() { AvaloniaXamlLoader.Load(this); @@ -36,5 +47,16 @@ namespace IntegrationTestApp ownerRect.Text = $"{owner.Position}, {PixelSize.FromSize(owner.FrameSize!.Value, scaling)}"; } } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + _timer?.Stop(); + } + + private void TimerOnTick(object? sender, EventArgs e) + { + _orderTextBox!.Text = MacOSIntegration.GetOrderedIndex(this).ToString(); + } } } From d1b652213a944e1e2b254b475b5d5c6915ca2694 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 1 Sep 2022 22:33:39 +0200 Subject: [PATCH 05/12] Make sure child windows have unique titles/ids. --- samples/IntegrationTestApp/MainWindow.axaml.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/samples/IntegrationTestApp/MainWindow.axaml.cs b/samples/IntegrationTestApp/MainWindow.axaml.cs index 2085b5da2b..f72f83fcb8 100644 --- a/samples/IntegrationTestApp/MainWindow.axaml.cs +++ b/samples/IntegrationTestApp/MainWindow.axaml.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; using System.Linq; using Avalonia; +using Avalonia.Automation; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.VisualTree; +using Microsoft.CodeAnalysis; namespace IntegrationTestApp { @@ -63,6 +65,17 @@ namespace IntegrationTestApp WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex, }; + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) + { + // Make sure the windows have unique names and AutomationIds. + var existing = lifetime.Windows.OfType().Count(); + if (existing > 0) + { + AutomationProperties.SetAutomationId(window, window.Name + (existing + 1)); + window.Title += $" {existing + 1}"; + } + } + if (size.HasValue) { window.Width = size.Value.Width; From 1c4a994e2c8796096821c92c8137db0f85e8249f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 1 Sep 2022 22:36:12 +0200 Subject: [PATCH 06/12] Add failing test for #8878. And update the tests to use the value of `NSWindow.orderedIndex` exposed in 0cc0443d34567f0d20082eaee29625a732b93849 instead of relying on appium to give us a z-ordered list of windows. --- .../WindowTests_MacOS.cs | 89 +++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs b/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs index 4e5344dd25..7eeab2f7f2 100644 --- a/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs +++ b/tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.cs @@ -30,7 +30,7 @@ namespace Avalonia.IntegrationTests.Appium tab.Click(); return; } - catch (WebDriverException e) when (retry++ < 3) + catch (WebDriverException) when (retry++ < 3) { // MacOS sometimes seems to need a bit of time to get itself back in order after switching out // of fullscreen. @@ -49,19 +49,16 @@ namespace Avalonia.IntegrationTests.Appium { mainWindow.Click(); - var windows = _session.FindElements(By.XPath("XCUIElementTypeWindow")); - var mainWindowIndex = GetWindowOrder(windows, "MainWindow"); - var secondaryWindowIndex = GetWindowOrder(windows, "SecondaryWindow"); + var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); - Assert.Equal(0, secondaryWindowIndex); - Assert.Equal(1, mainWindowIndex); + Assert.Equal(1, secondaryWindowIndex); } } [PlatformFact(TestPlatforms.MacOS)] public void WindowOrder_Modal_Dialog_Stays_InFront_Of_Parent_When_Clicking_Resize_Grip() { - var mainWindow = FindWindow(_session, "MainWindow"); + var mainWindow = GetWindow("MainWindow"); using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Modal, WindowStartupLocation.Manual)) { @@ -70,24 +67,21 @@ namespace Avalonia.IntegrationTests.Appium .ClickAndHold() .Perform(); - var windows = _session.FindElements(By.XPath("XCUIElementTypeWindow")); - var mainWindowIndex = GetWindowOrder(windows, "MainWindow"); - var secondaryWindowIndex = GetWindowOrder(windows, "SecondaryWindow"); + var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); new Actions(_session) .MoveToElement(mainWindow, 100, 1) .Release() .Perform(); - Assert.Equal(0, secondaryWindowIndex); - Assert.Equal(1, mainWindowIndex); + Assert.Equal(1, secondaryWindowIndex); } } [PlatformFact(TestPlatforms.MacOS)] public void WindowOrder_Modal_Dialog_Stays_InFront_Of_Parent_When_In_Fullscreen() { - var mainWindow = FindWindow(_session, "MainWindow"); + var mainWindow = GetWindow("MainWindow"); var buttons = mainWindow.GetChromeButtons(); buttons.maximize.Click(); @@ -98,14 +92,8 @@ namespace Avalonia.IntegrationTests.Appium { using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Modal, WindowStartupLocation.Manual)) { - var windows = _session.FindElements(By.XPath("XCUIElementTypeWindow")); - var mainWindowIndex = GetWindowOrder(windows, "MainWindow"); - var secondaryWindowIndex = GetWindowOrder(windows, "SecondaryWindow"); - - Assert.Equal(0, secondaryWindowIndex); - Assert.Equal(1, mainWindowIndex); - - Thread.Sleep(5000); + var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); + Assert.Equal(1, secondaryWindowIndex); } } finally @@ -122,13 +110,8 @@ namespace Avalonia.IntegrationTests.Appium using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Owned, WindowStartupLocation.Manual)) { mainWindow.Click(); - - var windows = _session.FindElements(By.XPath("XCUIElementTypeWindow")); - var mainWindowIndex = GetWindowOrder(windows, "MainWindow"); - var secondaryWindowIndex = GetWindowOrder(windows, "SecondaryWindow"); - - Assert.Equal(0, secondaryWindowIndex); - Assert.Equal(1, mainWindowIndex); + var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); + Assert.Equal(1, secondaryWindowIndex); } } @@ -141,22 +124,35 @@ namespace Avalonia.IntegrationTests.Appium { mainWindow.Click(); - var windows = _session.FindElements(By.XPath("XCUIElementTypeWindow")); - var mainWindowIndex = GetWindowOrder(windows, "MainWindow"); - var secondaryWindowIndex = GetWindowOrder(windows, "SecondaryWindow"); + var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); - Assert.Equal(1, secondaryWindowIndex); - Assert.Equal(0, mainWindowIndex); + Assert.Equal(2, secondaryWindowIndex); var sendToBack = _session.FindElementByAccessibilityId("SendToBack"); sendToBack.Click(); } } + [PlatformFact(TestPlatforms.MacOS)] + public void WindowOrder_Owned_Is_Correct_After_Closing_Window() + { + using (OpenWindow(new PixelSize(300, 500), ShowWindowMode.Owned, WindowStartupLocation.CenterOwner)) + { + // Open a second child window, and close it. + using (OpenWindow(new PixelSize(200, 200), ShowWindowMode.Owned, WindowStartupLocation.CenterOwner)) + { + } + + var secondaryWindowIndex = GetWindowOrder("SecondaryWindow"); + + Assert.Equal(1, secondaryWindowIndex); + } + } + [PlatformFact(TestPlatforms.MacOS)] public void Parent_Window_Has_Disabled_ChromeButtons_When_Modal_Dialog_Shown() { - var window = FindWindow(_session, "MainWindow"); + var window = GetWindow("MainWindow"); var (closeButton, miniaturizeButton, zoomButton) = window.GetChromeButtons(); Assert.True(closeButton.Enabled); @@ -176,7 +172,7 @@ namespace Avalonia.IntegrationTests.Appium { using (OpenWindow(new PixelSize(200, 100), ShowWindowMode.Modal, WindowStartupLocation.CenterOwner)) { - var secondaryWindow = FindWindow(_session, "SecondaryWindow"); + var secondaryWindow = GetWindow("SecondaryWindow"); var (closeButton, miniaturizeButton, zoomButton) = secondaryWindow.GetChromeButtons(); Assert.True(closeButton.Enabled); @@ -192,7 +188,7 @@ namespace Avalonia.IntegrationTests.Appium { using (OpenWindow(new PixelSize(200, 100), mode, WindowStartupLocation.Manual)) { - var secondaryWindow = FindWindow(_session, "SecondaryWindow"); + var secondaryWindow = GetWindow("SecondaryWindow"); var (_, miniaturizeButton, _) = secondaryWindow.GetChromeButtons(); miniaturizeButton.Click(); @@ -220,7 +216,7 @@ namespace Avalonia.IntegrationTests.Appium // causes Appium to think it's a different window. OpenWindow(null, ShowWindowMode.Owned, WindowStartupLocation.Manual); - var secondaryWindow = FindWindow(_session, "SecondaryWindow"); + var secondaryWindow = GetWindow("SecondaryWindow"); var hideButton = secondaryWindow.FindElementByAccessibilityId("HideButton"); hideButton.Click(); @@ -236,7 +232,7 @@ namespace Avalonia.IntegrationTests.Appium _session.FindElementByAccessibilityId("RestoreAll").Click(); // Close the window manually. - secondaryWindow = FindWindow(_session, "SecondaryWindow"); + secondaryWindow = GetWindow("SecondaryWindow"); secondaryWindow.GetChromeButtons().close.Click(); } @@ -259,18 +255,19 @@ namespace Avalonia.IntegrationTests.Appium return showButton.OpenWindowWithClick(); } - private static int GetWindowOrder(IReadOnlyCollection elements, string identifier) + private AppiumWebElement GetWindow(string identifier) { - return elements.TakeWhile(x => - x.FindElementByXPath("XCUIElementTypeWindow")?.GetAttribute("identifier") != identifier).Count(); + // The Avalonia a11y tree currently exposes two nested Window elements, this is a bug and should be fixed + // but in the meantime use the `parent::' selector to return the parent "real" window. + return _session.FindElementByXPath( + $"XCUIElementTypeWindow//*[@identifier='{identifier}']/parent::XCUIElementTypeWindow"); } - private static AppiumWebElement FindWindow(AppiumDriver session, string identifier) + private int GetWindowOrder(string identifier) { - var windows = session.FindElementsByXPath("XCUIElementTypeWindow"); - return windows.First(x => - x.FindElementsByXPath("XCUIElementTypeWindow") - .Any(y => y.GetAttribute("identifier") == identifier)); + var window = GetWindow(identifier); + var order = window.FindElementByXPath("//*[@identifier='Order']"); + return int.Parse(order.Text); } public enum ShowWindowMode From b83b795f57f625b8d9e794008ea14c612dbb79f8 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 1 Sep 2022 22:38:47 +0200 Subject: [PATCH 07/12] Don't bring old parent window to front. When a window is closed, its parent window is set to null, which caused this code to run. This line caused the parent window to be brought to front, and should have also caused any other child windows to be brought to front, but it seems OSX ignored those requests, causing #8878. Simply don't bring the parent window to the front when a child window is closed. I couldn't work out why this code was necessary anyway, and all integration tests still pass. Fixes #8878. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index af8c53cb33..ddc50c26b6 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -91,8 +91,6 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { if(_parent != nullptr) { _parent->_children.remove(this); - - _parent->BringToFront(); } auto cparent = dynamic_cast(parent); From f69ae35158819d7040e9dec6da9f2f840840015f Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Wed, 7 Sep 2022 16:46:22 +0300 Subject: [PATCH 08/12] Fix unpredictable choice between methods when using method binding. --- .../Data/Core/Plugins/MethodAccessorPlugin.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs index 1ca70140ec..0d51a6ed36 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs @@ -55,13 +55,20 @@ namespace Avalonia.Data.Core.Plugins var methods = type.GetMethods(bindingFlags); - foreach (MethodInfo methodInfo in methods) + foreach (var methodInfo in methods) { if (methodInfo.Name == methodName) { - found = methodInfo; - - break; + var parameters = methodInfo.GetParameters(); + if (parameters.Length == 1 && parameters[0].ParameterType == typeof(object)) + { + found = methodInfo; + break; + } + else if (parameters.Length == 0) + { + found = methodInfo; + } } } From b9f7270eb978258c60d95823cb5b263d17a32c38 Mon Sep 17 00:00:00 2001 From: Dmitry Zhelnin Date: Sun, 4 Sep 2022 22:22:09 +0300 Subject: [PATCH 09/12] TreeView: improve navigation with Left and Right keys --- src/Avalonia.Controls/TreeView.cs | 1 + src/Avalonia.Controls/TreeViewItem.cs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 7359f3cade..d78f9c82ef 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -495,6 +495,7 @@ namespace Avalonia.Controls break; case NavigationDirection.Down: + case NavigationDirection.Right: if (from?.IsExpanded == true && intoChildren && from.ItemCount > 0) { result = (TreeViewItem)from.ItemContainerGenerator.ContainerFromIndex(0)!; diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index 2e3aa037c2..ada081b808 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -157,17 +157,26 @@ namespace Avalonia.Controls switch (e.Key) { case Key.Right: - if (Items != null && Items.Cast().Any()) + if (Items != null && Items.Cast().Any() && !IsExpanded) { IsExpanded = true; + e.Handled = true; } - - e.Handled = true; break; case Key.Left: - IsExpanded = false; - e.Handled = true; + if (Items is not null && Items.Cast().Any() && IsExpanded) + { + if (IsFocused) + { + IsExpanded = false; + } + else + { + FocusManager.Instance?.Focus(this, NavigationMethod.Directional); + } + e.Handled = true; + } break; } } From 11ebe62c03b11832e596dc44a66388f3beddf675 Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Thu, 8 Sep 2022 13:08:04 +0300 Subject: [PATCH 10/12] Fix tests. --- .../ExpressionObserverBuilderTests_Method.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Method.cs b/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Method.cs index 72e0ac5e57..0e499ff256 100644 --- a/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Method.cs +++ b/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Method.cs @@ -19,12 +19,9 @@ namespace Avalonia.Markup.UnitTests.Parsers public int MethodWithReturn() => 0; - public int MethodWithReturnAndParameters(int i) => i; + public int MethodWithReturnAndParameter(object i) => (int)i; public static void StaticMethod() { } - - public static void ManyParameters(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) { } - public static int ManyParametersWithReturnType(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) => 1; } [Fact] @@ -42,10 +39,8 @@ namespace Avalonia.Markup.UnitTests.Parsers [Theory] [InlineData(nameof(TestObject.MethodWithoutReturn), typeof(Action))] [InlineData(nameof(TestObject.MethodWithReturn), typeof(Func))] - [InlineData(nameof(TestObject.MethodWithReturnAndParameters), typeof(Func))] + [InlineData(nameof(TestObject.MethodWithReturnAndParameter), typeof(Func))] [InlineData(nameof(TestObject.StaticMethod), typeof(Action))] - [InlineData(nameof(TestObject.ManyParameters), typeof(Action))] - [InlineData(nameof(TestObject.ManyParametersWithReturnType), typeof(Func))] public async Task Should_Get_Method_WithCorrectDelegateType(string methodName, Type expectedType) { var data = new TestObject(); @@ -61,10 +56,10 @@ namespace Avalonia.Markup.UnitTests.Parsers public async Task Can_Call_Method_Returned_From_Observer() { var data = new TestObject(); - var observer = ExpressionObserverBuilder.Build(data, nameof(TestObject.MethodWithReturnAndParameters)); + var observer = ExpressionObserverBuilder.Build(data, nameof(TestObject.MethodWithReturnAndParameter)); var result = await observer.Take(1); - var callback = (Func)result; + var callback = (Func)result; Assert.Equal(1, callback(1)); From 426f4e1e64fb7367d102d4ac9511ef741a2becd8 Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Thu, 8 Sep 2022 13:35:51 +0300 Subject: [PATCH 11/12] Fix Tests. --- .../Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs index 7931912649..f17903d24b 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs @@ -198,7 +198,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data public event PropertyChangedEventHandler PropertyChanged; public string Method() => Value = "Called"; - public string Method1(int i) => Value = $"Called {i}"; + public string Method1(object i) => Value = $"Called {i}"; public string Method2(int i, int j) => Value = $"Called {i},{j}"; public string Value { get; private set; } = "Not called"; From d59a998440002a91159cb184d85e9f8cece3d883 Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Thu, 8 Sep 2022 15:32:58 +0300 Subject: [PATCH 12/12] Add test. --- .../Data/BindingTests_Method.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs index f17903d24b..d51d6122cd 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs @@ -141,6 +141,28 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data } } + [Fact] + public void Binding_Method_Preserves_Correct_Order() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + +