From 3054a513ee33ec96c9220b57817721226522838f Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 25 Oct 2019 16:44:36 +0300 Subject: [PATCH 1/7] Fix AppBuilderBase.Start --- src/Avalonia.Controls/AppBuilderBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index d9be9171ed..85eab3be7b 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -126,8 +126,7 @@ namespace Avalonia.Controls // Copy-pasted because we can't call extension methods due to generic constraints var lifetime = new ClassicDesktopStyleApplicationLifetime(Instance) {ShutdownMode = ShutdownMode.OnMainWindowClose}; - Instance.ApplicationLifetime = lifetime; - SetupWithoutStarting(); + SetupWithLifetime(lifetime); lifetime.Start(Array.Empty()); } From b9bd57e25bb99430622a7c2c91f2a4e9904b6c74 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 25 Oct 2019 19:09:48 +0300 Subject: [PATCH 2/7] Removed `Application` parameter from ClassicDesktopStyleApplicationLifetime since it wasn't used anyway --- src/Avalonia.Controls/AppBuilderBase.cs | 2 +- .../ClassicDesktopStyleApplicationLifetime.cs | 9 ++++----- .../DesktopStyleApplicationLifetimeTests.cs | 18 +++++++++--------- .../AutoSuspendHelperTest.cs | 6 +++--- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 85eab3be7b..3b644191c2 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -125,7 +125,7 @@ namespace Avalonia.Controls }); // Copy-pasted because we can't call extension methods due to generic constraints - var lifetime = new ClassicDesktopStyleApplicationLifetime(Instance) {ShutdownMode = ShutdownMode.OnMainWindowClose}; + var lifetime = new ClassicDesktopStyleApplicationLifetime() {ShutdownMode = ShutdownMode.OnMainWindowClose}; SetupWithLifetime(lifetime); lifetime.Start(Array.Empty()); } diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs index 2533191ae4..6dd5b8cc81 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs @@ -5,12 +5,12 @@ using System.Threading; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Interactivity; +using Avalonia.Threading; namespace Avalonia.Controls.ApplicationLifetimes { public class ClassicDesktopStyleApplicationLifetime : IClassicDesktopStyleApplicationLifetime, IDisposable { - private readonly Application _app; private int _exitCode; private CancellationTokenSource _cts; private bool _isShuttingDown; @@ -34,12 +34,11 @@ namespace Avalonia.Controls.ApplicationLifetimes _activeLifetime?._windows.Add((Window)sender); } - public ClassicDesktopStyleApplicationLifetime(Application app) + public ClassicDesktopStyleApplicationLifetime() { if (_activeLifetime != null) throw new InvalidOperationException( "Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed"); - _app = app; _activeLifetime = this; } @@ -103,7 +102,7 @@ namespace Avalonia.Controls.ApplicationLifetimes Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args)); _cts = new CancellationTokenSource(); MainWindow?.Show(); - _app.Run(_cts.Token); + Dispatcher.UIThread.MainLoop(_cts.Token); Environment.ExitCode = _exitCode; return _exitCode; } @@ -124,7 +123,7 @@ namespace Avalonia this T builder, string[] args, ShutdownMode shutdownMode = ShutdownMode.OnLastWindowClose) where T : AppBuilderBase, new() { - var lifetime = new ClassicDesktopStyleApplicationLifetime(builder.Instance) {ShutdownMode = shutdownMode}; + var lifetime = new ClassicDesktopStyleApplicationLifetime() {ShutdownMode = shutdownMode}; builder.SetupWithLifetime(lifetime); return lifetime.Start(args); } diff --git a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs index 74523d4193..dee7a84812 100644 --- a/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs @@ -16,7 +16,7 @@ namespace Avalonia.Controls.UnitTests public void Should_Set_ExitCode_After_Shutdown() { using (UnitTestApplication.Start(TestServices.MockThreadingInterface)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { lifetime.Shutdown(1337); @@ -31,7 +31,7 @@ namespace Avalonia.Controls.UnitTests public void Should_Close_All_Remaining_Open_Windows_After_Explicit_Exit_Call() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var windows = new List { new Window(), new Window(), new Window(), new Window() }; @@ -50,7 +50,7 @@ namespace Avalonia.Controls.UnitTests public void Should_Only_Exit_On_Explicit_Exit() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { lifetime.ShutdownMode = ShutdownMode.OnExplicitShutdown; @@ -84,7 +84,7 @@ namespace Avalonia.Controls.UnitTests public void Should_Exit_After_MainWindow_Closed() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { lifetime.ShutdownMode = ShutdownMode.OnMainWindowClose; @@ -112,7 +112,7 @@ namespace Avalonia.Controls.UnitTests public void Should_Exit_After_Last_Window_Closed() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { lifetime.ShutdownMode = ShutdownMode.OnLastWindowClose; @@ -142,7 +142,7 @@ namespace Avalonia.Controls.UnitTests public void Show_Should_Add_Window_To_OpenWindows() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var window = new Window(); @@ -156,7 +156,7 @@ namespace Avalonia.Controls.UnitTests public void Window_Should_Be_Added_To_OpenWindows_Only_Once() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var window = new Window(); @@ -174,7 +174,7 @@ namespace Avalonia.Controls.UnitTests public void Close_Should_Remove_Window_From_OpenWindows() { using (UnitTestApplication.Start(TestServices.StyledWindow)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var window = new Window(); @@ -197,7 +197,7 @@ namespace Avalonia.Controls.UnitTests windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); using (UnitTestApplication.Start(services)) - using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using(var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var window = new Window(); diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs index 56b14c3936..c263a80ef3 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AutoSuspendHelperTest.cs @@ -45,7 +45,7 @@ namespace Avalonia.ReactiveUI.UnitTests public void AutoSuspendHelper_Should_Immediately_Fire_IsLaunchingNew() { using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) - using (var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using (var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var isLaunchingReceived = false; var application = AvaloniaLocator.Current.GetService(); @@ -86,7 +86,7 @@ namespace Avalonia.ReactiveUI.UnitTests public void ShouldPersistState_Should_Fire_On_App_Exit_When_SuspensionDriver_Is_Initialized() { using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) - using (var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) + using (var lifetime = new ClassicDesktopStyleApplicationLifetime()) { var shouldPersistReceived = false; var application = AvaloniaLocator.Current.GetService(); @@ -105,4 +105,4 @@ namespace Avalonia.ReactiveUI.UnitTests } } } -} \ No newline at end of file +} From 9c5e688958c2f2590644d8e54f1951d92d8551c6 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 27 Oct 2019 22:13:49 +0100 Subject: [PATCH 3/7] Fix Grid shared scope not being updated when resizing row/column definitions. --- src/Avalonia.Controls/ColumnDefinition.cs | 4 ++- src/Avalonia.Controls/DefinitionBase.cs | 33 +++++++++++++++-- src/Avalonia.Controls/RowDefinition.cs | 4 ++- .../Avalonia.Controls.UnitTests/GridTests.cs | 35 +++++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Controls/ColumnDefinition.cs b/src/Avalonia.Controls/ColumnDefinition.cs index 6cad357e93..293b6326d6 100644 --- a/src/Avalonia.Controls/ColumnDefinition.cs +++ b/src/Avalonia.Controls/ColumnDefinition.cs @@ -31,7 +31,9 @@ namespace Avalonia.Controls /// static ColumnDefinition() { - AffectsParentMeasure(WidthProperty, MinWidthProperty, MaxWidthProperty); + AffectsParentMeasure(MinWidthProperty, MaxWidthProperty); + + WidthProperty.Changed.AddClassHandler(OnUserSizePropertyChanged); } /// diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index 6ad32f080a..0b45d7e16a 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -7,9 +7,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; - -using Avalonia; -using Avalonia.Collections; using Avalonia.Utilities; namespace Avalonia.Controls @@ -118,6 +115,36 @@ namespace Avalonia.Controls } } + /// + /// This method needs to be internal to be accessable from derived classes. + /// + internal static void OnUserSizePropertyChanged(DefinitionBase definition, AvaloniaPropertyChangedEventArgs e) + { + if (definition.Parent == null) + { + return; + } + + if (definition._sharedState != null) + { + definition._sharedState.Invalidate(); + } + else + { + GridUnitType oldUnitType = ((GridLength)e.OldValue).GridUnitType; + GridUnitType newUnitType = ((GridLength)e.NewValue).GridUnitType; + + if (oldUnitType != newUnitType) + { + definition.Parent.Invalidate(); + } + else + { + definition.Parent.InvalidateMeasure(); + } + } + } + /// /// Returns true if this definition is a part of shared group. /// diff --git a/src/Avalonia.Controls/RowDefinition.cs b/src/Avalonia.Controls/RowDefinition.cs index 1a1a7e770b..85e7ed6519 100644 --- a/src/Avalonia.Controls/RowDefinition.cs +++ b/src/Avalonia.Controls/RowDefinition.cs @@ -31,7 +31,9 @@ namespace Avalonia.Controls /// static RowDefinition() { - AffectsParentMeasure(HeightProperty, MaxHeightProperty, MinHeightProperty); + AffectsParentMeasure(MaxHeightProperty, MinHeightProperty); + + HeightProperty.Changed.AddClassHandler(OnUserSizePropertyChanged); } /// diff --git a/tests/Avalonia.Controls.UnitTests/GridTests.cs b/tests/Avalonia.Controls.UnitTests/GridTests.cs index a2d6f14b26..353bb9c98d 100644 --- a/tests/Avalonia.Controls.UnitTests/GridTests.cs +++ b/tests/Avalonia.Controls.UnitTests/GridTests.cs @@ -1172,6 +1172,41 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(0, grids[0].ColumnDefinitions[0].ActualWidth); } + [Fact] + public void Size_Group_Definition_Resizes_Are_Tracked() + { + var grids = new[] { + CreateGrid(("A", new GridLength(5, GridUnitType.Pixel)), (null, new GridLength())), + CreateGrid(("A", new GridLength(5, GridUnitType.Pixel)), (null, new GridLength())) }; + var scope = new Grid(); + foreach (var xgrids in grids) + scope.Children.Add(xgrids); + + var root = new Grid(); + root.UseLayoutRounding = false; + root.SetValue(Grid.IsSharedSizeScopeProperty, true); + root.Children.Add(scope); + + root.Measure(new Size(50, 50)); + root.Arrange(new Rect(new Point(), new Point(50, 50))); + + PrintColumnDefinitions(grids[0]); + Assert.Equal(5, grids[0].ColumnDefinitions[0].ActualWidth); + Assert.Equal(5, grids[1].ColumnDefinitions[0].ActualWidth); + + grids[0].ColumnDefinitions[0].Width = new GridLength(10, GridUnitType.Pixel); + + foreach (Grid grid in grids) + { + grid.Measure(new Size(50, 50)); + grid.Arrange(new Rect(new Point(), new Point(50, 50))); + } + + PrintColumnDefinitions(grids[0]); + Assert.Equal(10, grids[0].ColumnDefinitions[0].ActualWidth); + Assert.Equal(10, grids[1].ColumnDefinitions[0].ActualWidth); + } + [Fact] public void Collection_Changes_Are_Tracked() { From 969166422eff8622f2f48963cf169f9f39b40c7d Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 27 Oct 2019 22:23:38 +0100 Subject: [PATCH 4/7] Comment fix. --- src/Avalonia.Controls/DefinitionBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index 0b45d7e16a..e4ae777453 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -116,7 +116,7 @@ namespace Avalonia.Controls } /// - /// This method needs to be internal to be accessable from derived classes. + /// Notifies parent or size scope that definition size has been changed. /// internal static void OnUserSizePropertyChanged(DefinitionBase definition, AvaloniaPropertyChangedEventArgs e) { From 5fea821c94e210f72c4f8c0c1aa812a6ce8a4c14 Mon Sep 17 00:00:00 2001 From: mstr2 Date: Mon, 28 Oct 2019 22:48:12 +0100 Subject: [PATCH 5/7] Failing test for bug #3170 --- .../AvaloniaObjectTests_Validation.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs index 2cf1eb1a97..f0e93dbb3a 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs @@ -78,6 +78,18 @@ namespace Avalonia.Base.UnitTests Assert.Equal(10, target.GetValue(Class1.AttachedProperty)); } + [Fact] + public void PropertyChanged_Event_Uses_Coerced_Value() + { + var inst = new Class1(); + inst.PropertyChanged += (sender, e) => + { + Assert.Equal(10, e.NewValue); + }; + + inst.SetValue(Class1.QuxProperty, 15); + } + private class Class1 : AvaloniaObject { public static readonly StyledProperty QuxProperty = From e46cb674234d60cae9da83d11733c98617722c3e Mon Sep 17 00:00:00 2001 From: mstr2 Date: Mon, 28 Oct 2019 22:50:01 +0100 Subject: [PATCH 6/7] Fixed a bug where ValueStore.Changed could be called with pre-validation value --- src/Avalonia.Base/ValueStore.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 1bdbd4ca7c..e06c5996c9 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -57,7 +57,8 @@ namespace Avalonia { if (priority == (int)BindingPriority.LocalValue) { - _propertyValues.SetValue(property, Validate(property, value)); + Validate(property, ref value); + _propertyValues.SetValue(property, value); Changed(property, priority, v, value); return; } @@ -78,7 +79,8 @@ namespace Avalonia if (priority == (int)BindingPriority.LocalValue) { - _propertyValues.AddValue(property, Validate(property, value)); + Validate(property, ref value); + _propertyValues.AddValue(property, value); Changed(property, priority, AvaloniaProperty.UnsetValue, value); return; } @@ -166,16 +168,14 @@ namespace Avalonia validate2); } - private object Validate(AvaloniaProperty property, object value) + private void Validate(AvaloniaProperty property, ref object value) { var validate = ((IStyledPropertyAccessor)property).GetValidationFunc(_owner.GetType()); if (validate != null && value != AvaloniaProperty.UnsetValue) { - return validate(_owner, value); + value = validate(_owner, value); } - - return value; } private DeferredSetter GetDeferredSetter(AvaloniaProperty property) From e27c7c0fff35b04663cff08bdb75e848e8501990 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 29 Oct 2019 10:21:14 +0300 Subject: [PATCH 7/7] Fixed parameter order in OnSelectionChanged in AutoCompleteBox Apparently Silverlight has different constructor argument order --- src/Avalonia.Controls/AutoCompleteBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs index ce4358648b..64db832a81 100644 --- a/src/Avalonia.Controls/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox.cs @@ -704,7 +704,7 @@ namespace Avalonia.Controls added.Add(e.NewValue); } - OnSelectionChanged(new SelectionChangedEventArgs(SelectionChangedEvent, removed, added)); + OnSelectionChanged(new SelectionChangedEventArgs(SelectionChangedEvent, added, removed)); } ///