diff --git a/src/Controls/src/Core/Window/Window.cs b/src/Controls/src/Core/Window/Window.cs index be74cc503588..3d37a59e2e8f 100644 --- a/src/Controls/src/Core/Window/Window.cs +++ b/src/Controls/src/Core/Window/Window.cs @@ -9,6 +9,7 @@ using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; +using Microsoft.Maui.Layouts; namespace Microsoft.Maui.Controls { @@ -202,60 +203,57 @@ double GetSizeCoordinate(BindableProperty property) void IWindow.FrameChanged(Rect frame) { - var x = X; - var y = Y; - var width = Width; - var height = Height; - if (new Rect(x, y, width, height) == frame) + if (new Rect(X, Y, Width, Height) == frame) return; _batchFrameUpdate++; + bool shouldTriggerSizeChanged = (Width != frame.Width) || (Height != frame.Height); - SetPropertyChanging(XProperty, nameof(X), x, frame.X); - SetPropertyChanging(YProperty, nameof(Y), y, frame.Y); - SetPropertyChanging(WidthProperty, nameof(Width), width, frame.Width); - SetPropertyChanging(HeightProperty, nameof(Height), height, frame.Height); - - SetValueCore(XProperty, frame.X, SetValueFlags.None, SetValuePrivateFlags.Silent, SetterSpecificity.FromHandler); - SetValueCore(YProperty, frame.Y, SetValueFlags.None, SetValuePrivateFlags.Silent, SetterSpecificity.FromHandler); - SetValueCore(WidthProperty, frame.Width, SetValueFlags.None, SetValuePrivateFlags.Silent, SetterSpecificity.FromHandler); - SetValueCore(HeightProperty, frame.Height, SetValueFlags.None, SetValuePrivateFlags.Silent, SetterSpecificity.FromHandler); + X = frame.X; + Y = frame.Y; + Width = frame.Width; + Height = frame.Height; _batchFrameUpdate--; if (_batchFrameUpdate < 0) _batchFrameUpdate = 0; - if (_batchFrameUpdate == 0) + if (_batchFrameUpdate == 0 && shouldTriggerSizeChanged) { - SetPropertyChanged(XProperty, nameof(X), x, frame.X); - SetPropertyChanged(YProperty, nameof(Y), y, frame.Y); - SetPropertyChanged(WidthProperty, nameof(Width), width, frame.Width); - SetPropertyChanged(HeightProperty, nameof(Height), height, frame.Height); - SizeChanged?.Invoke(this, EventArgs.Empty); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void SetPropertyChanging(BindableProperty property, string name, double oldValue, double newValue) + + // If for some reason during the PropertyChanged event on X,Y,Width,Height + // the user has changed these values. Then we need to propagate them back to the handler + UpdateHandler(X != frame.X, nameof(X)); + UpdateHandler(Y != frame.Y, nameof(Y)); + UpdateHandler(Width != frame.Width, nameof(Width)); + UpdateHandler(Height != frame.Height, nameof(Height)); + + + void UpdateHandler(bool condition, string property) { - if (oldValue == newValue) + if (Handler is null || !condition) + { return; + } - property.PropertyChanging?.Invoke(this, oldValue, newValue); - OnPropertyChanging(name); + Handler.UpdateValue(property); } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void SetPropertyChanged(BindableProperty property, string name, double oldValue, double newValue) + private protected override void UpdateHandlerValue(string property) + { + if (_batchFrameUpdate > 0 && (property == nameof(X) || property == nameof(Y) || property == nameof(Width) || property == nameof(Height))) { - if (oldValue == newValue) - return; - - OnPropertyChanged(name); - property.PropertyChanged?.Invoke(this, oldValue, newValue); + return; } + + base.UpdateHandlerValue(property); } + public event EventHandler? ModalPopped; public event EventHandler? ModalPopping; public event EventHandler? ModalPushed; diff --git a/src/Controls/tests/Core.UnitTests/WindowsTests.cs b/src/Controls/tests/Core.UnitTests/WindowsTests.cs index 3270ef24b39e..0e9a15993097 100644 --- a/src/Controls/tests/Core.UnitTests/WindowsTests.cs +++ b/src/Controls/tests/Core.UnitTests/WindowsTests.cs @@ -449,6 +449,20 @@ public void SettingCoreFrameOnlyFiresEventOnce() Assert.Equal(new[] { "X", "Y", "Width", "Height" }, changedProperties); } + [Fact] + public void MovingWindowDoNotTriggerSizeChanged() + { + var sizeChangedCount = 0; + + var window = new TestWindow(); + window.SizeChanged += (sender, e) => sizeChangedCount++; + + ((IWindow)window).FrameChanged(new Rect(100, 200, 300, 400)); + ((IWindow)window).FrameChanged(new Rect(200, 300, 300, 400)); + + Assert.Equal(1, sizeChangedCount); + } + [Fact] public void SettingSameCoreFrameDoesNothing() { @@ -486,7 +500,7 @@ public void UpdatingSingleCoordinateOnlyFiresSinglePropertyAndFrameEvent() ((IWindow)window).FrameChanged(new Rect(100, 250, 300, 400)); - Assert.Equal(1, sizeChangedCount); + Assert.Equal(0, sizeChangedCount); Assert.Equal(new[] { "Y" }, changingProperties); Assert.Equal(new[] { "Y" }, changedProperties); }