diff --git a/_omnisharp.sln b/_omnisharp.sln
index 945ac66ae337..ac54a4835477 100644
--- a/_omnisharp.sln
+++ b/_omnisharp.sln
@@ -94,6 +94,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Controls.Foldable", "src\Co
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maps", "src\Core\maps\src\Maps.csproj", "{1C9F9D5A-2CF7-4ADB-A9F5-672ACC05B035}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Graphics", "Graphics", "{E4884871-4A1B-43BC-814F-E3D6E52B1673}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{42AB9AE1-631D-4AD4-85B7-910FF0940BDB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{936C47A9-A7EA-4FBD-8733-CED1D4100E69}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics", "src\Graphics\src\Graphics\Graphics.csproj", "{CF056C95-51C4-4366-9D06-41D2B15EFEE4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics.Tests", "src\Graphics\tests\Graphics.Tests\Graphics.Tests.csproj", "{56BBFDBD-254F-42B6-9984-46E19C53FB00}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -211,6 +221,14 @@ Global
{1C9F9D5A-2CF7-4ADB-A9F5-672ACC05B035}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C9F9D5A-2CF7-4ADB-A9F5-672ACC05B035}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C9F9D5A-2CF7-4ADB-A9F5-672ACC05B035}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CF056C95-51C4-4366-9D06-41D2B15EFEE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CF056C95-51C4-4366-9D06-41D2B15EFEE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CF056C95-51C4-4366-9D06-41D2B15EFEE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CF056C95-51C4-4366-9D06-41D2B15EFEE4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {56BBFDBD-254F-42B6-9984-46E19C53FB00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {56BBFDBD-254F-42B6-9984-46E19C53FB00}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {56BBFDBD-254F-42B6-9984-46E19C53FB00}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {56BBFDBD-254F-42B6-9984-46E19C53FB00}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -254,6 +272,10 @@ Global
{50BCB5CD-DC2A-42AA-B921-D99B19625CE1} = {C564DDD6-DE79-45CD-88EA-3F690481572A}
{F0A48792-ACD7-4B72-83EB-C56A70FA5A3A} = {50C758FE-4E10-409A-94F5-A75480960864}
{1C9F9D5A-2CF7-4ADB-A9F5-672ACC05B035} = {E8AD265B-3C67-4640-AC58-A522F9FB3361}
+ {42AB9AE1-631D-4AD4-85B7-910FF0940BDB} = {E4884871-4A1B-43BC-814F-E3D6E52B1673}
+ {936C47A9-A7EA-4FBD-8733-CED1D4100E69} = {E4884871-4A1B-43BC-814F-E3D6E52B1673}
+ {CF056C95-51C4-4366-9D06-41D2B15EFEE4} = {42AB9AE1-631D-4AD4-85B7-910FF0940BDB}
+ {56BBFDBD-254F-42B6-9984-46E19C53FB00} = {936C47A9-A7EA-4FBD-8733-CED1D4100E69}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0B8ABEAD-D2B5-4370-A187-62B5ABE4EE50}
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml
index 80509c7c9def..657927b81ee9 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml
@@ -4,18 +4,44 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Pages.MultiWindowPage"
xmlns:views="clr-namespace:Maui.Controls.Sample.Pages.Base">
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml.cs
index 620c79e485f6..4dd2a9b7c174 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml.cs
@@ -1,18 +1,17 @@
using System;
using Maui.Controls.Sample.Pages.Base;
using Microsoft.Maui.Controls;
+using Microsoft.Maui.Devices;
namespace Maui.Controls.Sample.Pages
{
public partial class MultiWindowPage : BasePage
{
- static int windowCounter = 1;
-
public MultiWindowPage()
{
InitializeComponent();
- label.Text = "Window Count: " + (windowCounter++).ToString();
+ BindingContext = this;
}
void OnNewWindowClicked(object sender, EventArgs e)
@@ -22,9 +21,42 @@ void OnNewWindowClicked(object sender, EventArgs e)
void OnCloseWindowClicked(object sender, EventArgs e)
{
- var window = this.GetParentWindow();
- if (window is not null)
- Application.Current.CloseWindow(window);
+ Application.Current.CloseWindow(Window);
+ }
+
+ void OnSetMaxSize(object sender, EventArgs e)
+ {
+ Window.MaximumWidth = 800;
+ Window.MaximumHeight = 600;
+ }
+
+ void OnSetMinSize(object sender, EventArgs e)
+ {
+ Window.MinimumWidth = 640;
+ Window.MinimumHeight = 480;
+ }
+
+ void OnSetFreeSize(object sender, EventArgs e)
+ {
+ Window.MaximumWidth = double.PositiveInfinity;
+ Window.MaximumHeight = double.PositiveInfinity;
+
+ Window.MinimumWidth = -1d;
+ Window.MinimumHeight = -1d;
+ }
+
+ void OnSetCustomSize(object sender, EventArgs e)
+ {
+ Window.Width = 700;
+ Window.Height = 500;
+ }
+
+ void OnCenterWindow(object sender, EventArgs e)
+ {
+ var disp = DeviceDisplay.MainDisplayInfo;
+
+ Window.X = (disp.Width / disp.Density - Window.Width) / 2;
+ Window.Y = (disp.Height / disp.Density - Window.Height) / 2;
}
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs b/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs
index 560f7e6190ca..953c6784c2b1 100644
--- a/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs
+++ b/src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs
@@ -8,6 +8,7 @@
using System.Threading.Tasks;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform;
+using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Controls
{
@@ -25,6 +26,30 @@ public partial class Window : NavigableElement, IWindow, IVisualTreeElement, ITo
public static readonly BindableProperty FlowDirectionProperty =
BindableProperty.Create(nameof(FlowDirection), typeof(FlowDirection), typeof(Window), FlowDirection.MatchParent, propertyChanging: FlowDirectionChanging, propertyChanged: FlowDirectionChanged);
+ public static readonly BindableProperty XProperty = BindableProperty.Create(
+ nameof(X), typeof(double), typeof(Window), Primitives.Dimension.Unset);
+
+ public static readonly BindableProperty YProperty = BindableProperty.Create(
+ nameof(Y), typeof(double), typeof(Window), Primitives.Dimension.Unset);
+
+ public static readonly BindableProperty WidthProperty = BindableProperty.Create(
+ nameof(Width), typeof(double), typeof(Window), Primitives.Dimension.Unset);
+
+ public static readonly BindableProperty HeightProperty = BindableProperty.Create(
+ nameof(Height), typeof(double), typeof(Window), Primitives.Dimension.Unset);
+
+ public static readonly BindableProperty MaximumWidthProperty = BindableProperty.Create(
+ nameof(MaximumWidth), typeof(double), typeof(Window), Primitives.Dimension.Maximum);
+
+ public static readonly BindableProperty MaximumHeightProperty = BindableProperty.Create(
+ nameof(MaximumHeight), typeof(double), typeof(Window), Primitives.Dimension.Maximum);
+
+ public static readonly BindableProperty MinimumWidthProperty = BindableProperty.Create(
+ nameof(MinimumWidth), typeof(double), typeof(Window), Primitives.Dimension.Minimum);
+
+ public static readonly BindableProperty MinimumHeightProperty = BindableProperty.Create(
+ nameof(MinimumHeight), typeof(double), typeof(Window), Primitives.Dimension.Minimum);
+
HashSet _overlays = new HashSet();
ReadOnlyCollection? _logicalChildren;
List _visualChildren;
@@ -47,6 +72,8 @@ internal Toolbar? Toolbar
}
}
+ public event EventHandler? SizeChanged;
+
public IReadOnlyCollection Overlays => _overlays.ToList().AsReadOnly();
public IVisualDiagnosticsOverlay VisualDiagnosticsOverlay { get; }
@@ -86,6 +113,114 @@ public Page? Page
set => SetValue(PageProperty, value);
}
+ public double X
+ {
+ get => (double)GetValue(XProperty);
+ set => SetValue(XProperty, value);
+ }
+
+ public double Y
+ {
+ get => (double)GetValue(YProperty);
+ set => SetValue(YProperty, value);
+ }
+
+ public double Width
+ {
+ get => (double)GetValue(WidthProperty);
+ set => SetValue(WidthProperty, value);
+ }
+
+ public double Height
+ {
+ get => (double)GetValue(HeightProperty);
+ set => SetValue(HeightProperty, value);
+ }
+
+ public double MaximumWidth
+ {
+ get => (double)GetValue(MaximumWidthProperty);
+ set => SetValue(MaximumWidthProperty, value);
+ }
+
+ public double MaximumHeight
+ {
+ get => (double)GetValue(MaximumHeightProperty);
+ set => SetValue(MaximumHeightProperty, value);
+ }
+
+ public double MinimumWidth
+ {
+ get => (double)GetValue(MinimumWidthProperty);
+ set => SetValue(MinimumWidthProperty, value);
+ }
+
+ public double MinimumHeight
+ {
+ get => (double)GetValue(MinimumHeightProperty);
+ set => SetValue(MinimumHeightProperty, value);
+ }
+
+ double IWindow.X => GetPositionCoordinate(XProperty);
+
+ double IWindow.Y => GetPositionCoordinate(YProperty);
+
+ double IWindow.Width => GetSizeCoordinate(WidthProperty);
+
+ double IWindow.Height => GetSizeCoordinate(HeightProperty);
+
+ double IWindow.MaximumWidth => GetSizeCoordinate(MaximumWidthProperty);
+
+ double IWindow.MaximumHeight => GetSizeCoordinate(MaximumHeightProperty);
+
+ double IWindow.MinimumWidth => GetSizeCoordinate(MinimumWidthProperty);
+
+ double IWindow.MinimumHeight => GetSizeCoordinate(MinimumHeightProperty);
+
+ double GetPositionCoordinate(BindableProperty property)
+ {
+ if (!IsSet(property))
+ return Primitives.Dimension.Unset;
+ var coord = (double)GetValue(property);
+ if (!Primitives.Dimension.IsExplicitSet(coord))
+ return Primitives.Dimension.Unset;
+ return coord;
+ }
+
+ double GetSizeCoordinate(BindableProperty property)
+ {
+ if (!IsSet(property))
+ return Primitives.Dimension.Unset;
+ var coord = (double)GetValue(property);
+ if (coord == -1 || !Primitives.Dimension.IsExplicitSet(coord))
+ return Primitives.Dimension.Unset;
+ return ValidatePositive(coord);
+ }
+
+ int _batchFrameUpdate = 0;
+
+ void IWindow.FrameChanged(Rect frame)
+ {
+ if (new Rect(X, Y, Width, Height) == frame)
+ return;
+
+ _batchFrameUpdate++;
+
+ X = frame.X;
+ Y = frame.Y;
+ Width = frame.Width;
+ Height = frame.Height;
+
+ _batchFrameUpdate--;
+ if (_batchFrameUpdate < 0)
+ _batchFrameUpdate = 0;
+
+ if (_batchFrameUpdate == 0)
+ {
+ SizeChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
public event EventHandler? ModalPopped;
public event EventHandler? ModalPopping;
public event EventHandler? ModalPushed;
@@ -519,6 +654,11 @@ bool IWindow.BackButtonClicked()
return this.Page?.SendBackButtonPressed() ?? false;
}
+ static double ValidatePositive(double value, [CallerMemberName] string? name = null) =>
+ value >= 0
+ ? value
+ : throw new InvalidOperationException($"{name} cannot be less than zero.");
+
class NavigationImpl : NavigationProxy
{
readonly Window _owner;
diff --git a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
index d1b058beee4a..f9cc0f11b0ce 100644
--- a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -34,6 +34,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -51,6 +68,14 @@ static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerExitedCo
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandParameterProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
virtual Microsoft.Maui.Controls.PointerEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 165288a581f9..f6d93c17a9c1 100644
--- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -34,6 +34,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -56,6 +73,14 @@ static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCom
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
virtual Microsoft.Maui.Controls.PointerEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index 165288a581f9..f6d93c17a9c1 100644
--- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -34,6 +34,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -56,6 +73,14 @@ static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCom
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
virtual Microsoft.Maui.Controls.PointerEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index 1d4a2e697c91..e298ec589c0c 100644
--- a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -47,6 +47,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -76,6 +93,14 @@ static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCom
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
virtual Microsoft.Maui.Controls.PointerEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index b54632c31405..23ed5fe756cd 100644
--- a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -37,6 +37,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -62,6 +79,14 @@ virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Contr
~override Microsoft.Maui.Controls.Platform.ShellNavigationViewItemAutomationPeer.GetChildrenCore() -> System.Collections.Generic.IList
~override Microsoft.Maui.Controls.Platform.ShellNavigationViewItemAutomationPeer.GetLabeledByCore() -> Microsoft.UI.Xaml.Automation.Peers.AutomationPeer
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls.BindableObject! bindable) -> object!
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
diff --git a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
index 6d21ea4f2f46..86a159e1dbef 100644
--- a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -34,6 +34,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -55,6 +72,14 @@ static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCom
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
virtual Microsoft.Maui.Controls.PointerEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
diff --git a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 6d21ea4f2f46..86a159e1dbef 100644
--- a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -34,6 +34,23 @@ Microsoft.Maui.Controls.TapGestureRecognizer.Tapped -> System.EventHandler Microsoft.Maui.Controls.ButtonsMask
Microsoft.Maui.Controls.ToolTipProperties
Microsoft.Maui.Controls.ToolTipProperties.ToolTipProperties() -> void
+Microsoft.Maui.Controls.Window.Height.get -> double
+Microsoft.Maui.Controls.Window.Height.set -> void
+Microsoft.Maui.Controls.Window.MaximumHeight.get -> double
+Microsoft.Maui.Controls.Window.MaximumHeight.set -> void
+Microsoft.Maui.Controls.Window.MaximumWidth.get -> double
+Microsoft.Maui.Controls.Window.MaximumWidth.set -> void
+Microsoft.Maui.Controls.Window.MinimumHeight.get -> double
+Microsoft.Maui.Controls.Window.MinimumHeight.set -> void
+Microsoft.Maui.Controls.Window.MinimumWidth.get -> double
+Microsoft.Maui.Controls.Window.MinimumWidth.set -> void
+Microsoft.Maui.Controls.Window.SizeChanged -> System.EventHandler?
+Microsoft.Maui.Controls.Window.Width.get -> double
+Microsoft.Maui.Controls.Window.Width.set -> void
+Microsoft.Maui.Controls.Window.X.get -> double
+Microsoft.Maui.Controls.Window.X.set -> void
+Microsoft.Maui.Controls.Window.Y.get -> double
+Microsoft.Maui.Controls.Window.Y.set -> void
override Microsoft.Maui.Controls.ContentPresenter.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.ContentPresenter.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
override Microsoft.Maui.Controls.FlyoutPage.OnDisappearing() -> void
@@ -55,6 +72,14 @@ static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCom
static readonly Microsoft.Maui.Controls.PointerGestureRecognizer.PointerMovedCommandProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.HeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MaximumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumHeightProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.MinimumWidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.WidthProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.XProperty -> Microsoft.Maui.Controls.BindableProperty!
+static readonly Microsoft.Maui.Controls.Window.YProperty -> Microsoft.Maui.Controls.BindableProperty!
virtual Microsoft.Maui.Controls.PointerEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
virtual Microsoft.Maui.Controls.TappedEventArgs.GetPosition(Microsoft.Maui.Controls.Element? relativeTo) -> Microsoft.Maui.Graphics.Point?
~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
diff --git a/src/Controls/tests/Core.UnitTests/WindowsTests.cs b/src/Controls/tests/Core.UnitTests/WindowsTests.cs
index 6e32283cecf3..bd5608518967 100644
--- a/src/Controls/tests/Core.UnitTests/WindowsTests.cs
+++ b/src/Controls/tests/Core.UnitTests/WindowsTests.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using Microsoft.Maui.Graphics;
using Xunit;
namespace Microsoft.Maui.Controls.Core.UnitTests
@@ -352,5 +353,153 @@ void ValidateSetup(Application app, Page page = null)
Assert.Equal(app.NavigationProxy, window.NavigationProxy.Inner);
Assert.Equal(window.NavigationProxy, page.NavigationProxy.Inner);
}
+
+ [Fact]
+ public void SettingCoreFrameOnlyFiresEventOnce()
+ {
+ var sizeChangedCount = 0;
+ var propertyChanges = new List();
+
+ var window = new TestWindow();
+ window.SizeChanged += (sender, e) => sizeChangedCount++;
+ window.PropertyChanged += (sender, e) => propertyChanges.Add(e.PropertyName);
+
+ ((IWindow)window).FrameChanged(new Rect(100, 200, 300, 400));
+
+ Assert.Equal(1, sizeChangedCount);
+ Assert.Equal(new[] { "X", "Y", "Width", "Height" }, propertyChanges);
+ }
+
+ [Fact]
+ public void SettingSameCoreFrameDoesNothing()
+ {
+ var sizeChangedCount = 0;
+ var propertyChanges = new List();
+
+ var window = new TestWindow();
+ ((IWindow)window).FrameChanged(new Rect(100, 200, 300, 400));
+
+ window.SizeChanged += (sender, e) => sizeChangedCount++;
+ window.PropertyChanged += (sender, e) => propertyChanges.Add(e.PropertyName);
+
+ ((IWindow)window).FrameChanged(new Rect(100, 200, 300, 400));
+
+ Assert.Equal(0, sizeChangedCount);
+ Assert.Empty(propertyChanges);
+ }
+
+ [Fact]
+ public void UpdatingSingleCoordinateOnlyFiresSinglePropertyAndFrameEvent()
+ {
+ var sizeChangedCount = 0;
+ var propertyChanges = new List();
+
+ var window = new TestWindow();
+ ((IWindow)window).FrameChanged(new Rect(100, 200, 300, 400));
+
+ window.SizeChanged += (sender, e) => sizeChangedCount++;
+ window.PropertyChanged += (sender, e) => propertyChanges.Add(e.PropertyName);
+
+ ((IWindow)window).FrameChanged(new Rect(100, 250, 300, 400));
+
+ Assert.Equal(1, sizeChangedCount);
+ Assert.Equal(new[] { "Y" }, propertyChanges);
+ }
+
+ [Fact]
+ public void UpdatingSingleBoundOnlyFiresSingleProperty()
+ {
+ var sizeChangedCount = 0;
+ var propertyChanges = new List();
+
+ var window = new TestWindow();
+ ((IWindow)window).FrameChanged(new Rect(100, 200, 300, 400));
+
+ window.SizeChanged += (sender, e) => sizeChangedCount++;
+ window.PropertyChanged += (sender, e) => propertyChanges.Add(e.PropertyName);
+
+ ((IWindow)window).FrameChanged(new Rect(100, 200, 350, 400));
+
+ Assert.Equal(1, sizeChangedCount);
+ Assert.Equal(new[] { "Width" }, propertyChanges);
+ }
+
+ [Fact]
+ public void DefaultBoundsArePassedToCoreCorrectly()
+ {
+ var controlsWindow = new TestWindow();
+ var coreWindow = controlsWindow as IWindow;
+
+ Assert.Equal(double.NaN, coreWindow.X);
+ Assert.Equal(double.NaN, coreWindow.Y);
+ Assert.Equal(double.NaN, coreWindow.Width);
+ Assert.Equal(double.NaN, coreWindow.Height);
+
+ Assert.Equal(double.NaN, coreWindow.MinimumWidth);
+ Assert.Equal(double.NaN, coreWindow.MinimumHeight);
+
+ Assert.Equal(double.NaN, coreWindow.MaximumWidth);
+ Assert.Equal(double.NaN, coreWindow.MaximumHeight);
+ }
+
+ [Theory]
+ [InlineData(double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN)]
+ [InlineData(-1, -1, -1, -1, -1, -1, double.NaN, double.NaN)]
+ [InlineData(0, 0, 100, 100, 0, 0, 100, 100)]
+ public void BoundsArePassedToCoreCorrectly(double inX, double inY, double inW, double inH, double outX, double outY, double outW, double outH)
+ {
+ var controlsWindow = new TestWindow
+ {
+ X = inX,
+ Y = inY,
+ Width = inW,
+ Height = inH
+ };
+
+ var coreWindow = controlsWindow as IWindow;
+
+ Assert.Equal(outX, coreWindow.X);
+ Assert.Equal(outY, coreWindow.Y);
+ Assert.Equal(outW, coreWindow.Width);
+ Assert.Equal(outH, coreWindow.Height);
+ }
+
+ [Theory]
+ [InlineData(double.NaN, double.NaN, double.NaN, double.NaN)]
+ [InlineData(-1, -1, double.NaN, double.NaN)]
+ [InlineData(100, 100, 100, 100)]
+ [InlineData(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity)]
+ public void MaxDimensionsArePassedToCoreCorrectly(double inW, double inH, double outW, double outH)
+ {
+ var controlsWindow = new TestWindow
+ {
+ MaximumWidth = inW,
+ MaximumHeight = inH
+ };
+
+ var coreWindow = controlsWindow as IWindow;
+
+ Assert.Equal(outW, coreWindow.MaximumWidth);
+ Assert.Equal(outH, coreWindow.MaximumHeight);
+ }
+
+ [Theory]
+ [InlineData(double.NaN, double.NaN, double.NaN, double.NaN)]
+ [InlineData(-1, -1, double.NaN, double.NaN)]
+ [InlineData(100, 100, 100, 100)]
+ [InlineData(0, 0, 0, 0)]
+ public void MinDimensionsArePassedToCoreCorrectly(double inW, double inH, double outW, double outH)
+ {
+ var controlsWindow = new TestWindow
+ {
+ MinimumWidth = inW,
+ MinimumHeight = inH
+ };
+
+ var coreWindow = controlsWindow as IWindow;
+
+ Assert.Equal(outW, coreWindow.MinimumWidth);
+ Assert.Equal(outH, coreWindow.MinimumHeight);
+ }
}
}
diff --git a/src/Core/src/Core/IWindow.cs b/src/Core/src/Core/IWindow.cs
index b5ec7308f529..e11bb6524afc 100644
--- a/src/Core/src/Core/IWindow.cs
+++ b/src/Core/src/Core/IWindow.cs
@@ -1,3 +1,4 @@
+using Microsoft.Maui.Graphics;
using System.Collections.Generic;
namespace Microsoft.Maui
@@ -22,6 +23,46 @@ public interface IWindow : ITitledElement
///
IReadOnlyCollection Overlays { get; }
+ ///
+ /// Gets the specified X coordinate of the IWindow.
+ ///
+ double X { get; }
+
+ ///
+ /// Gets the specified Y coordinate of the IWindow.
+ ///
+ double Y { get; }
+
+ ///
+ /// Gets the specified width of the IWindow.
+ ///
+ double Width { get; }
+
+ ///
+ /// Gets the specified minimum width constraint of the IWindow, between zero and double.PositiveInfinity.
+ ///
+ double MinimumWidth { get; }
+
+ ///
+ /// Gets the specified maximum width constraint of the IWindow, between zero and double.PositiveInfinity.
+ ///
+ double MaximumWidth { get; }
+
+ ///
+ /// Gets the specified height of the IWindow.
+ ///
+ double Height { get; }
+
+ ///
+ /// Gets the specified minimum height constraint of the IWindow, between zero and double.PositiveInfinity.
+ ///
+ double MinimumHeight { get; }
+
+ ///
+ /// Gets the specified maximum height constraint of the IWindow, between zero and double.PositiveInfinity.
+ ///
+ double MaximumHeight { get; }
+
///
/// Adds a Window Overlay to the current Window.
///
@@ -81,6 +122,8 @@ public interface IWindow : ITitledElement
void DisplayDensityChanged(float displayDensity);
+ void FrameChanged(Rect frame);
+
float RequestDisplayDensity();
}
}
\ No newline at end of file
diff --git a/src/Core/src/Handlers/Window/WindowHandler.Windows.cs b/src/Core/src/Handlers/Window/WindowHandler.Windows.cs
index b57d6fbdf4fe..b10c04f251b7 100644
--- a/src/Core/src/Handlers/Window/WindowHandler.Windows.cs
+++ b/src/Core/src/Handlers/Window/WindowHandler.Windows.cs
@@ -1,4 +1,7 @@
using System;
+using Microsoft.Maui.Graphics;
+using Microsoft.UI.Windowing;
+using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Maui.ApplicationModel;
@@ -12,6 +15,19 @@ protected override void ConnectHandler(UI.Xaml.Window platformView)
if (platformView.Content is null)
platformView.Content = new WindowRootViewContainer();
+
+ // update the platform window with the user size
+ platformView.UpdateSize(VirtualView);
+
+ var appWindow = platformView.GetAppWindow();
+ if (appWindow is not null)
+ {
+ // then pass the actual size back to the user
+ UpdateVirtualViewFrame(appWindow);
+
+ // THEN attach the event to reduce churn
+ appWindow.Changed += OnWindowChanged;
+ }
}
protected override void DisconnectHandler(UI.Xaml.Window platformView)
@@ -26,6 +42,10 @@ protected override void DisconnectHandler(UI.Xaml.Window platformView)
platformView.Content = null;
}
+ var appWindow = platformView.GetAppWindow();
+ if (appWindow is not null)
+ appWindow.Changed -= OnWindowChanged;
+
base.DisconnectHandler(platformView);
}
@@ -54,6 +74,30 @@ public static void MapContent(IWindowHandler handler, IWindow window)
window.VisualDiagnosticsOverlay.Initialize();
}
+ public static void MapX(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateX(view);
+
+ public static void MapY(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateY(view);
+
+ public static void MapWidth(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateWidth(view);
+
+ public static void MapHeight(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateHeight(view);
+
+ public static void MapMaximumWidth(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMaximumWidth(view);
+
+ public static void MapMaximumHeight(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMaximumHeight(view);
+
+ public static void MapMinimumWidth(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMinimumWidth(view);
+
+ public static void MapMinimumHeight(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMinimumHeight(view);
+
public static void MapToolbar(IWindowHandler handler, IWindow view)
{
if (view is IToolbarElement tb)
@@ -91,5 +135,25 @@ public static void MapRequestDisplayDensity(IWindowHandler handler, IWindow wind
if (args is DisplayDensityRequest request)
request.SetResult(handler.PlatformView.GetDisplayDensity());
}
+
+ void OnWindowChanged(AppWindow sender, AppWindowChangedEventArgs args)
+ {
+ if (!args.DidSizeChange && !args.DidPositionChange)
+ return;
+
+ UpdateVirtualViewFrame(sender);
+ }
+
+ void UpdateVirtualViewFrame(AppWindow appWindow)
+ {
+ var size = appWindow.Size;
+ var pos = appWindow.Position;
+
+ var density = PlatformView.GetDisplayDensity();
+
+ VirtualView.FrameChanged(new Rect(
+ pos.X / density, pos.Y / density,
+ size.Width / density, size.Height / density));
+ }
}
}
\ No newline at end of file
diff --git a/src/Core/src/Handlers/Window/WindowHandler.cs b/src/Core/src/Handlers/Window/WindowHandler.cs
index 754897c4e752..8b583982da13 100644
--- a/src/Core/src/Handlers/Window/WindowHandler.cs
+++ b/src/Core/src/Handlers/Window/WindowHandler.cs
@@ -18,6 +18,16 @@ public partial class WindowHandler : IWindowHandler
{
[nameof(IWindow.Title)] = MapTitle,
[nameof(IWindow.Content)] = MapContent,
+#if WINDOWS || MACCATALYST
+ [nameof(IWindow.X)] = MapX,
+ [nameof(IWindow.Y)] = MapY,
+ [nameof(IWindow.Width)] = MapWidth,
+ [nameof(IWindow.Height)] = MapHeight,
+ [nameof(IWindow.MaximumWidth)] = MapMaximumWidth,
+ [nameof(IWindow.MaximumHeight)] = MapMaximumHeight,
+ [nameof(IWindow.MinimumWidth)] = MapMinimumWidth,
+ [nameof(IWindow.MinimumHeight)] = MapMinimumHeight,
+#endif
#if ANDROID || WINDOWS || TIZEN
[nameof(IToolbarElement.Toolbar)] = MapToolbar,
#endif
diff --git a/src/Core/src/Handlers/Window/WindowHandler.iOS.cs b/src/Core/src/Handlers/Window/WindowHandler.iOS.cs
index f3bb4aa975d4..ba037d41097d 100644
--- a/src/Core/src/Handlers/Window/WindowHandler.iOS.cs
+++ b/src/Core/src/Handlers/Window/WindowHandler.iOS.cs
@@ -20,6 +20,34 @@ public static void MapContent(IWindowHandler handler, IWindow window)
window.VisualDiagnosticsOverlay.Initialize();
}
+#if MACCATALYST
+
+ public static void MapX(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateX(view);
+
+ public static void MapY(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateY(view);
+
+ public static void MapWidth(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateWidth(view);
+
+ public static void MapHeight(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateHeight(view);
+
+ public static void MapMaximumWidth(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMaximumWidth(view);
+
+ public static void MapMaximumHeight(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMaximumHeight(view);
+
+ public static void MapMinimumWidth(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMinimumWidth(view);
+
+ public static void MapMinimumHeight(IWindowHandler handler, IWindow view) =>
+ handler.PlatformView?.UpdateMinimumHeight(view);
+
+#endif
+
public static void MapMenuBar(IWindowHandler handler, IWindow view)
{
if (!(OperatingSystem.IsIOSVersionAtLeast(13) || OperatingSystem.IsMacCatalystVersionAtLeast(13)))
diff --git a/src/Core/src/Platform/Windows/MauiWinUIWindow.cs b/src/Core/src/Platform/Windows/MauiWinUIWindow.cs
index 174fdf1398a9..95f6b4db0590 100644
--- a/src/Core/src/Platform/Windows/MauiWinUIWindow.cs
+++ b/src/Core/src/Platform/Windows/MauiWinUIWindow.cs
@@ -6,15 +6,20 @@
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml.Controls;
+using Windows.Graphics;
namespace Microsoft.Maui
{
- public class MauiWinUIWindow : UI.Xaml.Window
+ public class MauiWinUIWindow : UI.Xaml.Window, IPlatformSizeRestrictedWindow
{
+ static readonly SizeInt32 DefaultMinimumSize = new SizeInt32(0, 0);
+ static readonly SizeInt32 DefaultMaximumSize = new SizeInt32(int.MaxValue, int.MaxValue);
+
readonly WindowMessageManager _windowManager;
IntPtr _windowIcon;
bool _enableResumeEvent;
+ UI.Xaml.UIElement? _customTitleBar;
public MauiWinUIWindow()
{
@@ -85,12 +90,52 @@ void OnWindowMessage(object? sender, WindowMessageEventArgs e)
}
else if (e.MessageId == PlatformMethods.MessageIds.WM_DPICHANGED)
{
- var dpiX = (short)(long)e.WParam;
- var dpiY = (short)((long)e.WParam >> 16);
-
var window = this.GetWindow();
if (window is not null)
- window.DisplayDensityChanged(dpiX / DeviceDisplay.BaseLogicalDpi);
+ {
+ var dpiX = (short)(long)e.WParam;
+ var dpiY = (short)((long)e.WParam >> 16);
+
+ var density = dpiX / DeviceDisplay.BaseLogicalDpi;
+
+ window.DisplayDensityChanged(density);
+ }
+ }
+ else if (e.MessageId == PlatformMethods.MessageIds.WM_GETMINMAXINFO)
+ {
+ var win = this as IPlatformSizeRestrictedWindow;
+ var minSize = win.MinimumSize;
+ var maxSize = win.MaximumSize;
+
+ var changedMinSize = minSize != DefaultMinimumSize;
+ var changedMaxSize = maxSize != DefaultMaximumSize;
+
+ if (changedMinSize || changedMaxSize)
+ {
+ var rect = Marshal.PtrToStructure(e.LParam);
+
+ if (changedMinSize)
+ {
+ var newMinSize = new PlatformMethods.POINT
+ {
+ X = Math.Max(minSize.Width, rect.MinTrackSize.X),
+ Y = Math.Max(minSize.Height, rect.MinTrackSize.Y)
+ };
+ rect.MinTrackSize = newMinSize;
+ }
+
+ if (changedMaxSize)
+ {
+ var newMaxSize = new PlatformMethods.POINT
+ {
+ X = Math.Min(maxSize.Width, rect.MaxTrackSize.X),
+ Y = Math.Min(maxSize.Height, rect.MaxTrackSize.Y)
+ };
+ rect.MaxTrackSize = newMaxSize;
+ }
+
+ Marshal.StructureToPtr(rect, e.LParam, true);
+ }
}
MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents(
@@ -122,7 +167,10 @@ void SetIcon()
}
}
- UI.Xaml.UIElement? _customTitleBar;
+ SizeInt32 IPlatformSizeRestrictedWindow.MinimumSize { get; set; } = DefaultMinimumSize;
+
+ SizeInt32 IPlatformSizeRestrictedWindow.MaximumSize { get; set; } = DefaultMaximumSize;
+
internal UI.Xaml.UIElement? MauiCustomTitleBar
{
get => _customTitleBar;
@@ -143,11 +191,17 @@ internal void UpdateTitleOnCustomTitleBar()
}
}
-
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
static extern IntPtr ExtractAssociatedIcon(IntPtr hInst, string iconPath, ref IntPtr index);
[DllImport("user32.dll", SetLastError = true)]
static extern int DestroyIcon(IntPtr hIcon);
}
+
+ interface IPlatformSizeRestrictedWindow
+ {
+ SizeInt32 MinimumSize { get; set; }
+
+ SizeInt32 MaximumSize { get; set; }
+ }
}
diff --git a/src/Core/src/Platform/Windows/WindowExtensions.cs b/src/Core/src/Platform/Windows/WindowExtensions.cs
index 572b37501f82..8a0c574b435d 100644
--- a/src/Core/src/Platform/Windows/WindowExtensions.cs
+++ b/src/Core/src/Platform/Windows/WindowExtensions.cs
@@ -1,10 +1,9 @@
using System;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Devices;
-using System.Threading.Tasks;
-using Microsoft.Maui.Media;
-using WinRT.Interop;
+using Windows.Graphics;
using Windows.Graphics.Display;
+using WinRT.Interop;
namespace Microsoft.Maui.Platform
{
@@ -18,6 +17,156 @@ public static void UpdateTitle(this UI.Xaml.Window platformWindow, IWindow windo
mauiWindow.UpdateTitleOnCustomTitleBar();
}
+ public static void UpdateX(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdatePosition(window);
+
+ public static void UpdateY(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdatePosition(window);
+
+ public static void UpdatePosition(this UI.Xaml.Window platformWindow, IWindow window)
+ {
+ var appWindow = platformWindow.GetAppWindow();
+ if (appWindow is null)
+ return;
+
+ var density = platformWindow.GetDisplayDensity();
+ var x = window.X;
+ var y = window.Y;
+
+ var currPos = appWindow.Position;
+ x = Primitives.Dimension.IsExplicitSet(x)
+ ? Math.Round(x * density)
+ : currPos.X;
+ y = Primitives.Dimension.IsExplicitSet(y)
+ ? Math.Round(y * density)
+ : currPos.Y;
+
+ var pos = new PointInt32(
+ (int)x,
+ (int)y);
+
+ if (pos != currPos)
+ appWindow.Move(pos);
+ }
+
+ public static void UpdateWidth(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdateSize(window);
+
+ public static void UpdateHeight(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdateSize(window);
+
+ public static void UpdateSize(this UI.Xaml.Window platformWindow, IWindow window)
+ {
+ var appWindow = platformWindow.GetAppWindow();
+ if (appWindow is null)
+ return;
+
+ var density = platformWindow.GetDisplayDensity();
+ var width = window.Width;
+ var height = window.Height;
+
+ var currSize = appWindow.Size;
+ width = Primitives.Dimension.IsExplicitSet(width)
+ ? Math.Round(width * density)
+ : currSize.Width;
+ height = Primitives.Dimension.IsExplicitSet(height)
+ ? Math.Round(height * density)
+ : currSize.Height;
+
+ var size = new SizeInt32(
+ (int)width,
+ (int)height);
+
+ if (size != currSize)
+ appWindow.Resize(size);
+ }
+
+ public static void UpdateMinimumWidth(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdateMinimumSize(window);
+
+ public static void UpdateMinimumHeight(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdateMinimumSize(window);
+
+ public static void UpdateMinimumSize(this UI.Xaml.Window platformWindow, IWindow window)
+ {
+ if (platformWindow is not IPlatformSizeRestrictedWindow restrictedWindow)
+ return;
+
+ var density = platformWindow.GetDisplayDensity();
+ var minWidth = window.MinimumWidth;
+ var minHeight = window.MinimumHeight;
+
+ var actualMinWidth = double.IsFinite(minWidth)
+ ? (int)Math.Clamp(minWidth * density, 0, int.MaxValue)
+ : 0;
+
+ var actualMinHeight = double.IsFinite(minHeight)
+ ? (int)Math.Clamp(minHeight * density, 0, int.MaxValue)
+ : 0;
+
+ var minSize = new SizeInt32(
+ actualMinWidth,
+ actualMinHeight);
+
+ restrictedWindow.MinimumSize = minSize;
+
+ var appWindow = platformWindow.GetAppWindow();
+ if (appWindow is null)
+ return;
+
+ var currentSize = appWindow.Size;
+ var temp = currentSize;
+ if (currentSize.Width < actualMinWidth)
+ temp.Width = actualMinWidth;
+ if (currentSize.Height < actualMinHeight)
+ temp.Height = actualMinHeight;
+ if (currentSize != temp)
+ appWindow.Resize(temp);
+ }
+
+ public static void UpdateMaximumWidth(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdateMaximumSize(window);
+
+ public static void UpdateMaximumHeight(this UI.Xaml.Window platformWindow, IWindow window) =>
+ platformWindow.UpdateMaximumSize(window);
+
+ public static void UpdateMaximumSize(this UI.Xaml.Window platformWindow, IWindow window)
+ {
+ if (platformWindow is not IPlatformSizeRestrictedWindow restrictedWindow)
+ return;
+
+ var density = platformWindow.GetDisplayDensity();
+ var maxWidth = window.MaximumWidth;
+ var maxHeight = window.MaximumHeight;
+
+ var actualMaxWidth = double.IsFinite(maxWidth)
+ ? (int)Math.Clamp(maxWidth * density, 0, int.MaxValue)
+ : int.MaxValue;
+
+ var actualMaxHeight = double.IsFinite(maxHeight)
+ ? (int)Math.Clamp(maxHeight * density, 0, int.MaxValue)
+ : int.MaxValue;
+
+ var MaxSize = new SizeInt32(
+ actualMaxWidth,
+ actualMaxHeight);
+
+ restrictedWindow.MaximumSize = MaxSize;
+
+ var appWindow = platformWindow.GetAppWindow();
+ if (appWindow is null)
+ return;
+
+ var currentSize = appWindow.Size;
+ var temp = currentSize;
+ if (currentSize.Width > actualMaxWidth)
+ temp.Width = actualMaxWidth;
+ if (currentSize.Height > actualMaxHeight)
+ temp.Height = actualMaxHeight;
+ if (currentSize != temp)
+ appWindow.Resize(temp);
+ }
+
public static IWindow? GetWindow(this UI.Xaml.Window platformWindow)
{
foreach (var window in MauiWinUIApplication.Current.Application.Windows)
diff --git a/src/Core/src/Platform/iOS/MauiUISceneDelegate.cs b/src/Core/src/Platform/iOS/MauiUISceneDelegate.cs
index 1fb950d2176c..2eb0010a3c38 100644
--- a/src/Core/src/Platform/iOS/MauiUISceneDelegate.cs
+++ b/src/Core/src/Platform/iOS/MauiUISceneDelegate.cs
@@ -116,5 +116,21 @@ public virtual void DidUpdateUserActivity(UIScene scene, NSUserActivity userActi
[System.Runtime.Versioning.SupportedOSPlatform("maccatalyst15.0")]
public virtual void RestoreInteractionState(UIScene scene, NSUserActivity stateRestorationActivity) =>
GetServiceProvider()?.InvokeLifecycleEvents(del => del(scene, stateRestorationActivity));
+
+ [System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
+ [System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
+ [Export("windowScene:didUpdateCoordinateSpace:interfaceOrientation:traitCollection:")]
+ public virtual void DidUpdateCoordinateSpace(UIWindowScene windowScene, IUICoordinateSpace previousCoordinateSpace, UIInterfaceOrientation previousInterfaceOrientation, UITraitCollection previousTraitCollection)
+ {
+ var platformWindow = Window;
+ if (platformWindow is null)
+ return;
+
+ var window = platformWindow.GetWindow();
+ if (window is null)
+ return;
+
+ window.FrameChanged(platformWindow.Frame.ToRectangle());
+ }
}
}
\ No newline at end of file
diff --git a/src/Core/src/Platform/iOS/WindowExtensions.cs b/src/Core/src/Platform/iOS/WindowExtensions.cs
index 8c9a43bcaaef..22a1916403c2 100644
--- a/src/Core/src/Platform/iOS/WindowExtensions.cs
+++ b/src/Core/src/Platform/iOS/WindowExtensions.cs
@@ -9,6 +9,82 @@ namespace Microsoft.Maui.Platform
{
public static partial class WindowExtensions
{
+# if MACCATALYST
+
+ internal static void UpdateX(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateUnsupportedCoordinate(window);
+
+ internal static void UpdateY(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateUnsupportedCoordinate(window);
+
+ internal static void UpdateWidth(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateUnsupportedCoordinate(window);
+
+ internal static void UpdateHeight(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateUnsupportedCoordinate(window);
+
+ internal static void UpdateUnsupportedCoordinate(this UIWindow platformWindow, IWindow window)
+ {
+ if (!OperatingSystem.IsIOSVersionAtLeast(13))
+ return;
+
+ window.FrameChanged(platformWindow.Bounds.ToRectangle());
+ }
+
+ public static void UpdateMaximumWidth(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateMaximumSize(window.MaximumWidth, window.MaximumHeight);
+
+ public static void UpdateMaximumHeight(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateMaximumSize(window.MaximumWidth, window.MaximumHeight);
+
+ public static void UpdateMaximumSize(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateMaximumSize(window.MaximumWidth, window.MaximumHeight);
+
+ internal static void UpdateMaximumSize(this UIWindow platformWindow, double width, double height)
+ {
+ if (!OperatingSystem.IsIOSVersionAtLeast(13))
+ return;
+
+ var restrictions = platformWindow.WindowScene?.SizeRestrictions;
+ if (restrictions is null)
+ return;
+
+ if (!Primitives.Dimension.IsExplicitSet(width) || !Primitives.Dimension.IsMaximumSet(width))
+ width = double.MaxValue;
+ if (!Primitives.Dimension.IsExplicitSet(height) || !Primitives.Dimension.IsMaximumSet(height))
+ height = double.MaxValue;
+
+ restrictions.MaximumSize = new CoreGraphics.CGSize(width, height);
+ }
+
+ public static void UpdateMinimumWidth(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateMinimumSize(window.MinimumWidth, window.MinimumHeight);
+
+ public static void UpdateMinimumHeight(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateMinimumSize(window.MinimumWidth, window.MinimumHeight);
+
+ public static void UpdateMinimumSize(this UIWindow platformWindow, IWindow window) =>
+ platformWindow.UpdateMinimumSize(window.MinimumWidth, window.MinimumHeight);
+
+ internal static void UpdateMinimumSize(this UIWindow platformWindow, double width, double height)
+ {
+ if (!OperatingSystem.IsIOSVersionAtLeast(13))
+ return;
+
+ var restrictions = platformWindow.WindowScene?.SizeRestrictions;
+ if (restrictions is null)
+ return;
+
+ if (!Primitives.Dimension.IsExplicitSet(width) || !Primitives.Dimension.IsMinimumSet(width))
+ width = 0;
+ if (!Primitives.Dimension.IsExplicitSet(height) || !Primitives.Dimension.IsMinimumSet(height))
+ height = 0;
+
+ restrictions.MinimumSize = new CoreGraphics.CGSize(width, height);
+ }
+
+#endif
+
internal static IWindow? GetHostedWindow(this UIWindow? uiWindow)
{
if (uiWindow is null)
diff --git a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
index 88ee27217b2f..264003d13cd3 100644
--- a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -32,10 +32,19 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
Microsoft.Maui.ToolTip.ToolTip() -> void
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
override Microsoft.Maui.Handlers.MenuFlyoutHandler.CreatePlatformElement() -> object!
override Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CreatePlatformElement() -> object!
override Microsoft.Maui.Handlers.EditorHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void
diff --git a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 4145f5ca8a01..8ab8db54660e 100644
--- a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -32,6 +32,7 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
@@ -49,6 +50,14 @@ Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneOpenUrl
Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneRestoreInteractionState
Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneWillContinueUserActivity
Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneWillEnterForeground
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
Microsoft.Maui.Platform.MauiWKWebView.MauiWKWebView(CoreGraphics.CGRect frame, Microsoft.Maui.Handlers.WebViewHandler! handler, WebKit.WKWebViewConfiguration! configuration) -> void
Microsoft.Maui.Platform.MauiWKWebView.MauiWKWebView(Microsoft.Maui.Handlers.WebViewHandler! handler) -> void
override Microsoft.Maui.Handlers.BorderHandler.ConnectHandler(Microsoft.Maui.Platform.ContentView! platformView) -> void
@@ -116,7 +125,8 @@ virtual Microsoft.Maui.MauiUISceneDelegate.OpenUrl(UIKit.UIScene! scene, Foundat
virtual Microsoft.Maui.MauiUISceneDelegate.RestoreInteractionState(UIKit.UIScene! scene, Foundation.NSUserActivity! stateRestorationActivity) -> void
virtual Microsoft.Maui.MauiUISceneDelegate.WillContinueUserActivity(UIKit.UIScene! scene, string! userActivityType) -> void
virtual Microsoft.Maui.MauiUISceneDelegate.WillEnterForeground(UIKit.UIScene! scene) -> void
+virtual Microsoft.Maui.MauiUISceneDelegate.DidUpdateCoordinateSpace(UIKit.UIWindowScene! windowScene, UIKit.IUICoordinateSpace! previousCoordinateSpace, UIKit.UIInterfaceOrientation previousInterfaceOrientation, UIKit.UITraitCollection! previousTraitCollection) -> void
*REMOVED*static Microsoft.Maui.IViewExtensions.GetEffectiveFlowDirection(this Microsoft.Maui.IView! view) -> Microsoft.Maui.FlowDirection
*REMOVED*Microsoft.Maui.IViewExtensions
*REMOVED*static Microsoft.Maui.Layouts.LayoutExtensions.ShouldArrangeLeftToRight(this Microsoft.Maui.IView! view) -> bool
-*REMOVED*static Microsoft.Maui.Platform.TextAlignmentExtensions.AdjustForFlowDirection(this UIKit.UITextAlignment textAlignment, Microsoft.Maui.IView! view) -> UIKit.UITextAlignment
\ No newline at end of file
+*REMOVED*static Microsoft.Maui.Platform.TextAlignmentExtensions.AdjustForFlowDirection(this UIKit.UITextAlignment textAlignment, Microsoft.Maui.IView! view) -> UIKit.UITextAlignment
diff --git a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index fa95c0b7d75a..d8f6006210cd 100644
--- a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -32,6 +32,7 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
@@ -49,6 +50,14 @@ Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneOpenUrl
Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneRestoreInteractionState
Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneWillContinueUserActivity
Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneWillEnterForeground
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
Microsoft.Maui.Platform.MauiWKWebView.MauiWKWebView(CoreGraphics.CGRect frame, Microsoft.Maui.Handlers.WebViewHandler! handler, WebKit.WKWebViewConfiguration! configuration) -> void
Microsoft.Maui.Platform.MauiWKWebView.MauiWKWebView(Microsoft.Maui.Handlers.WebViewHandler! handler) -> void
override Microsoft.Maui.Handlers.BorderHandler.ConnectHandler(Microsoft.Maui.Platform.ContentView! platformView) -> void
@@ -80,6 +89,14 @@ static Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CommandMapper -> Micro
static Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.Mapper -> Microsoft.Maui.IPropertyMapper!
static Microsoft.Maui.Handlers.ViewHandler.MapToolTip(Microsoft.Maui.IViewHandler! handler, Microsoft.Maui.IView! view) -> void
static Microsoft.Maui.Handlers.ViewHandler.MapContextFlyout(Microsoft.Maui.IViewHandler! handler, Microsoft.Maui.IView! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapHeight(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMaximumHeight(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMaximumWidth(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMinimumHeight(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMinimumWidth(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapWidth(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapX(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapY(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
static Microsoft.Maui.LifecycleEvents.iOSLifecycleBuilderExtensions.SceneContinueUserActivity(this Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder! lifecycle, Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneContinueUserActivity! del) -> Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder!
static Microsoft.Maui.LifecycleEvents.iOSLifecycleBuilderExtensions.SceneDidEnterBackground(this Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder! lifecycle, Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneDidEnterBackground! del) -> Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder!
static Microsoft.Maui.LifecycleEvents.iOSLifecycleBuilderExtensions.SceneDidFailToContinueUserActivity(this Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder! lifecycle, Microsoft.Maui.LifecycleEvents.iOSLifecycle.SceneDidFailToContinueUserActivity! del) -> Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder!
@@ -93,6 +110,12 @@ static Microsoft.Maui.LifecycleEvents.iOSLifecycleBuilderExtensions.SceneWillEnt
static Microsoft.Maui.Platform.MauiWKWebView.CreateConfiguration() -> WebKit.WKWebViewConfiguration!
static Microsoft.Maui.Platform.ViewExtensions.UpdateBackground(this UIKit.UIView! platformView, Microsoft.Maui.Graphics.Paint? paint, Microsoft.Maui.IButtonStroke? stroke = null) -> void
static Microsoft.Maui.Platform.ViewExtensions.UpdateToolTip(this UIKit.UIView! platformView, Microsoft.Maui.ToolTip? tooltip) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMaximumHeight(this UIKit.UIWindow! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMaximumSize(this UIKit.UIWindow! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMaximumWidth(this UIKit.UIWindow! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMinimumHeight(this UIKit.UIWindow! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMinimumSize(this UIKit.UIWindow! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMinimumWidth(this UIKit.UIWindow! platformWindow, Microsoft.Maui.IWindow! window) -> void
virtual Microsoft.Maui.MauiUIApplicationDelegate.ApplicationSignificantTimeChange(UIKit.UIApplication! application) -> void
Microsoft.Maui.LifecycleEvents.iOSLifecycle.ApplicationSignificantTimeChange
static Microsoft.Maui.LifecycleEvents.iOSLifecycleBuilderExtensions.ApplicationSignificantTimeChange(this Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder! lifecycle, Microsoft.Maui.LifecycleEvents.iOSLifecycle.ApplicationSignificantTimeChange! del) -> Microsoft.Maui.LifecycleEvents.IiOSLifecycleBuilder!
@@ -116,7 +139,8 @@ virtual Microsoft.Maui.MauiUISceneDelegate.OpenUrl(UIKit.UIScene! scene, Foundat
virtual Microsoft.Maui.MauiUISceneDelegate.RestoreInteractionState(UIKit.UIScene! scene, Foundation.NSUserActivity! stateRestorationActivity) -> void
virtual Microsoft.Maui.MauiUISceneDelegate.WillContinueUserActivity(UIKit.UIScene! scene, string! userActivityType) -> void
virtual Microsoft.Maui.MauiUISceneDelegate.WillEnterForeground(UIKit.UIScene! scene) -> void
+virtual Microsoft.Maui.MauiUISceneDelegate.DidUpdateCoordinateSpace(UIKit.UIWindowScene! windowScene, UIKit.IUICoordinateSpace! previousCoordinateSpace, UIKit.UIInterfaceOrientation previousInterfaceOrientation, UIKit.UITraitCollection! previousTraitCollection) -> void
*REMOVED*static Microsoft.Maui.IViewExtensions.GetEffectiveFlowDirection(this Microsoft.Maui.IView! view) -> Microsoft.Maui.FlowDirection
*REMOVED*Microsoft.Maui.IViewExtensions
*REMOVED*static Microsoft.Maui.Layouts.LayoutExtensions.ShouldArrangeLeftToRight(this Microsoft.Maui.IView! view) -> bool
-*REMOVED*static Microsoft.Maui.Platform.TextAlignmentExtensions.AdjustForFlowDirection(this UIKit.UITextAlignment textAlignment, Microsoft.Maui.IView! view) -> UIKit.UITextAlignment
\ No newline at end of file
+*REMOVED*static Microsoft.Maui.Platform.TextAlignmentExtensions.AdjustForFlowDirection(this UIKit.UITextAlignment textAlignment, Microsoft.Maui.IView! view) -> UIKit.UITextAlignment
diff --git a/src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index ef47366a252a..9a13c3f01d9a 100644
--- a/src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -32,10 +32,19 @@ Microsoft.Maui.IContextFlyoutElement.ContextFlyout.get -> Microsoft.Maui.IFlyout
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
Microsoft.Maui.ToolTip.ToolTip() -> void
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
override Microsoft.Maui.Handlers.MenuFlyoutHandler.CreatePlatformElement() -> object!
override Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CreatePlatformElement() -> object!
static Microsoft.Maui.Handlers.MenuFlyoutHandler.CommandMapper -> Microsoft.Maui.CommandMapper!
diff --git a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index ce73cda655a3..b0a42d33f2db 100644
--- a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -33,10 +33,19 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
Microsoft.Maui.ToolTip.ToolTip() -> void
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
override Microsoft.Maui.Handlers.MenuFlyoutHandler.CreatePlatformElement() -> Microsoft.UI.Xaml.Controls.MenuFlyout!
override Microsoft.Maui.Handlers.MenuFlyoutHandler.SetVirtualView(Microsoft.Maui.IElement! view) -> void
override Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CreatePlatformElement() -> Microsoft.UI.Xaml.Controls.MenuFlyoutSeparator!
@@ -57,7 +66,27 @@ Microsoft.Maui.ScrollToRequest.HorizontalOffset.get -> double
Microsoft.Maui.ScrollToRequest.HorizontalOffset.init -> void
Microsoft.Maui.ScrollToRequest.ScrollToRequest(double HorizontalOffset, double VerticalOffset, bool Instant) -> void
static Microsoft.Maui.Handlers.ViewHandler.MapToolTip(Microsoft.Maui.IViewHandler! handler, Microsoft.Maui.IView! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapHeight(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMaximumHeight(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMaximumWidth(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMinimumHeight(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapMinimumWidth(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapWidth(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapX(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
+static Microsoft.Maui.Handlers.WindowHandler.MapY(Microsoft.Maui.Handlers.IWindowHandler! handler, Microsoft.Maui.IWindow! view) -> void
static Microsoft.Maui.Platform.ViewExtensions.UpdateToolTip(this Microsoft.UI.Xaml.FrameworkElement! platformView, Microsoft.Maui.ToolTip? tooltip) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateHeight(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMaximumHeight(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMaximumSize(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMaximumWidth(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMinimumHeight(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMinimumSize(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateMinimumWidth(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdatePosition(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateSize(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateWidth(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateX(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
+static Microsoft.Maui.Platform.WindowExtensions.UpdateY(this Microsoft.UI.Xaml.Window! platformWindow, Microsoft.Maui.IWindow! window) -> void
static Microsoft.Maui.Handlers.ViewHandler.MapContextFlyout(Microsoft.Maui.IViewHandler! handler, Microsoft.Maui.IView! view) -> void
*REMOVED*static Microsoft.Maui.IViewExtensions.GetEffectiveFlowDirection(this Microsoft.Maui.IView! view) -> Microsoft.Maui.FlowDirection
*REMOVED*Microsoft.Maui.IViewExtensions
diff --git a/src/Core/src/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net/PublicAPI.Unshipped.txt
index df8ddefc8f6a..e25c98297b21 100644
--- a/src/Core/src/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -32,10 +32,19 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
Microsoft.Maui.ToolTip.ToolTip() -> void
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
override Microsoft.Maui.Handlers.MenuFlyoutHandler.CreatePlatformElement() -> object!
override Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CreatePlatformElement() -> object!
static Microsoft.Maui.Handlers.MenuFlyoutHandler.CommandMapper -> Microsoft.Maui.CommandMapper!
diff --git a/src/Core/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 64cbb5dceb2a..1b337faf8fcb 100644
--- a/src/Core/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -32,10 +32,19 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
Microsoft.Maui.ToolTip.ToolTip() -> void
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
override Microsoft.Maui.Handlers.MenuFlyoutHandler.CreatePlatformElement() -> object!
override Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CreatePlatformElement() -> object!
static Microsoft.Maui.Handlers.MenuFlyoutHandler.CommandMapper -> Microsoft.Maui.CommandMapper!
diff --git a/src/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
index 64cbb5dceb2a..1b337faf8fcb 100644
--- a/src/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
@@ -32,10 +32,19 @@ Microsoft.Maui.IContextFlyoutElement
Microsoft.Maui.IMenuFlyoutSeparator
Microsoft.Maui.IToolTipElement
Microsoft.Maui.IToolTipElement.ToolTip.get -> Microsoft.Maui.ToolTip?
+Microsoft.Maui.IWindow.FrameChanged(Microsoft.Maui.Graphics.Rect frame) -> void
Microsoft.Maui.ToolTip
Microsoft.Maui.ToolTip.Content.get -> object?
Microsoft.Maui.ToolTip.Content.set -> void
Microsoft.Maui.ToolTip.ToolTip() -> void
+Microsoft.Maui.IWindow.Height.get -> double
+Microsoft.Maui.IWindow.Width.get -> double
+Microsoft.Maui.IWindow.MaximumHeight.get -> double
+Microsoft.Maui.IWindow.MaximumWidth.get -> double
+Microsoft.Maui.IWindow.MinimumHeight.get -> double
+Microsoft.Maui.IWindow.MinimumWidth.get -> double
+Microsoft.Maui.IWindow.X.get -> double
+Microsoft.Maui.IWindow.Y.get -> double
override Microsoft.Maui.Handlers.MenuFlyoutHandler.CreatePlatformElement() -> object!
override Microsoft.Maui.Handlers.MenuFlyoutSeparatorHandler.CreatePlatformElement() -> object!
static Microsoft.Maui.Handlers.MenuFlyoutHandler.CommandMapper -> Microsoft.Maui.CommandMapper!
diff --git a/src/Core/tests/Benchmarks/Stubs/WindowStub.cs b/src/Core/tests/Benchmarks/Stubs/WindowStub.cs
index 82297393687b..e45625a6d4e4 100644
--- a/src/Core/tests/Benchmarks/Stubs/WindowStub.cs
+++ b/src/Core/tests/Benchmarks/Stubs/WindowStub.cs
@@ -1,4 +1,5 @@
using System;
+using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Handlers.Benchmarks
{
@@ -18,6 +19,8 @@ public class WindowStub : StubBase, IWindow
public bool IsDestroyed { get; set; }
public bool IsResumed { get; set; }
public bool IsStopped { get; set; }
+ public double X { get; set; }
+ public double Y { get; set; }
public void Activated()
{
@@ -67,5 +70,8 @@ public void Backgrounding(IPersistedState state)
public float RequestDisplayDensity() => 1.0f;
public virtual void DisplayDensityChanged(float displayDensity) { }
+
+ public virtual void FrameChanged(Rect frame) =>
+ Frame = frame;
}
}
\ No newline at end of file
diff --git a/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.Windows.cs b/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.Windows.cs
index a806a0695b3a..af005c2f7043 100644
--- a/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.Windows.cs
+++ b/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.Windows.cs
@@ -1,17 +1,10 @@
using System;
using System.Threading.Tasks;
+using Microsoft.Maui.Controls;
using Microsoft.Maui.DeviceTests.Stubs;
-using Microsoft.Maui.Handlers;
-using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Controls;
+using Windows.Graphics;
using Xunit;
-using WBrush = Microsoft.UI.Xaml.Media.Brush;
-using WImageSource = Microsoft.UI.Xaml.Media.ImageSource;
-using WGrid = Microsoft.UI.Xaml.Controls.Grid;
-using WImage = Microsoft.UI.Xaml.Controls.Image;
-using WBorder = Microsoft.UI.Xaml.Controls.Border;
using WVisibility = Microsoft.UI.Xaml.Visibility;
-using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Maui.DeviceTests
{
@@ -25,85 +18,192 @@ public async Task BackButtonNotVisibleWithBasicView()
Content = new ButtonStub()
};
- await RunWindowTest(window, manager =>
+ await RunWindowStubTest(window, handler =>
{
- var navView = GetRootNavigationView(manager);
- Assert.Equal(NavigationViewBackButtonVisible.Collapsed, navView.IsBackButtonVisible);
- return Task.CompletedTask;
+ var navView = GetRootNavigationView(handler);
+ Assert.Equal(UI.Xaml.Controls.NavigationViewBackButtonVisible.Collapsed, navView.IsBackButtonVisible);
});
}
- [Theory(DisplayName = "MauiToolbar Control Visibilities Toggle")]
- [InlineData("titleIcon")]
- [InlineData("textBlockBorder")]
- [InlineData("menuContent")]
- [InlineData("titleView")]
- public async Task MauiToolbarControlVisibilitiesToggle(string controlName)
+ [Fact(DisplayName = "MauiToolbar titleIcon Visibility Toggle")]
+ public async Task MauiToolbarTitleIconVisibilityToggle()
{
await InvokeOnMainThreadAsync(async () =>
{
MauiToolbar mauiToolbar = new MauiToolbar();
- var toolbarContent = (DependencyObject)mauiToolbar.Content;
- var control = toolbarContent.GetDescendantByName(controlName);
+ var toolbarContent = (UI.Xaml.DependencyObject)mauiToolbar.Content;
+ var control = toolbarContent.GetDescendantByName("titleIcon");
Assert.Equal(WVisibility.Collapsed, control.Visibility);
- switch (controlName)
+ var tcs = new TaskCompletionSource();
+ var fileImageSource = new FileImageSource() { File = "black.png" };
+ fileImageSource.LoadImage(MauiContext, (result) =>
{
- case "titleIcon":
- var tcs = new TaskCompletionSource();
- var fileImageSource = new Controls.FileImageSource() { File = "black.png" };
- fileImageSource.LoadImage(MauiContext, (result) =>
- {
- mauiToolbar.TitleIconImageSource = result.Value;
- tcs.SetResult(true);
- });
-
- await tcs.Task;
- Assert.Equal(WVisibility.Visible, control.Visibility);
- mauiToolbar.TitleIconImageSource = null;
- Assert.Equal(WVisibility.Collapsed, control.Visibility);
- break;
- case "textBlockBorder":
- mauiToolbar.Title = "text";
- Assert.Equal(WVisibility.Visible, control.Visibility);
- mauiToolbar.Title = "";
- Assert.Equal(WVisibility.Collapsed, control.Visibility);
- break;
- case "menuContent":
- mauiToolbar.SetMenuBar(new MenuBar() { Items = { new MenuBarItem() } });
- Assert.Equal(WVisibility.Visible, control.Visibility);
- mauiToolbar.SetMenuBar(new MenuBar());
- Assert.Equal(WVisibility.Collapsed, control.Visibility);
- mauiToolbar.SetMenuBar(new MenuBar() { Items = { new MenuBarItem() } });
- Assert.Equal(WVisibility.Visible, control.Visibility);
- mauiToolbar.SetMenuBar(null);
- Assert.Equal(WVisibility.Collapsed, control.Visibility);
- break;
- case "titleView":
- mauiToolbar.TitleView = "text";
- Assert.Equal(WVisibility.Visible, control.Visibility);
- mauiToolbar.TitleView = null;
- Assert.Equal(WVisibility.Collapsed, control.Visibility);
- break;
+ mauiToolbar.TitleIconImageSource = result.Value;
+ tcs.SetResult(true);
+ });
+ await tcs.Task;
+
+ Assert.Equal(WVisibility.Visible, control.Visibility);
+
+ mauiToolbar.TitleIconImageSource = null;
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+ });
+ }
+
+ [Fact(DisplayName = "MauiToolbar textBlockBorder Visibility Toggle")]
+ public async Task MauiToolbarTextBlockBorderVisibilityToggle()
+ {
+ await InvokeOnMainThreadAsync(() =>
+ {
+ MauiToolbar mauiToolbar = new MauiToolbar();
+ var toolbarContent = (UI.Xaml.DependencyObject)mauiToolbar.Content;
+ var control = toolbarContent.GetDescendantByName("textBlockBorder");
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+
+ mauiToolbar.Title = "text";
+
+ Assert.Equal(WVisibility.Visible, control.Visibility);
+
+ mauiToolbar.Title = "";
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+ });
+ }
+
+ [Fact(DisplayName = "MauiToolbar menuContent Visibility Toggle")]
+ public async Task MauiToolbarMenuContentVisibilityToggle()
+ {
+ await InvokeOnMainThreadAsync(() =>
+ {
+ MauiToolbar mauiToolbar = new MauiToolbar();
+ var toolbarContent = (UI.Xaml.DependencyObject)mauiToolbar.Content;
+ var control = toolbarContent.GetDescendantByName("menuContent");
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+
+ mauiToolbar.SetMenuBar(new UI.Xaml.Controls.MenuBar() { Items = { new UI.Xaml.Controls.MenuBarItem() } });
+
+ Assert.Equal(WVisibility.Visible, control.Visibility);
+
+ mauiToolbar.SetMenuBar(new UI.Xaml.Controls.MenuBar());
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+
+ mauiToolbar.SetMenuBar(new UI.Xaml.Controls.MenuBar() { Items = { new UI.Xaml.Controls.MenuBarItem() } });
+
+ Assert.Equal(WVisibility.Visible, control.Visibility);
+
+ mauiToolbar.SetMenuBar(null);
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+ });
+ }
+
+ [Fact(DisplayName = "MauiToolbar titleView Visibility Toggle")]
+ public async Task MauiToolbarTitleViewVisibilityToggle()
+ {
+ await InvokeOnMainThreadAsync(() =>
+ {
+ MauiToolbar mauiToolbar = new MauiToolbar();
+ var toolbarContent = (UI.Xaml.DependencyObject)mauiToolbar.Content;
+ var control = toolbarContent.GetDescendantByName("titleView");
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+
+ mauiToolbar.TitleView = "text";
+
+ Assert.Equal(WVisibility.Visible, control.Visibility);
+
+ mauiToolbar.TitleView = null;
+
+ Assert.Equal(WVisibility.Collapsed, control.Visibility);
+ });
+ }
+
+ [Fact]
+ public async Task ContentIsSetInitially()
+ {
+ var window = new Window
+ {
+ Page = new ContentPage
+ {
+ Content = new Label { Text = "Yay!" }
}
+ };
+
+ await RunWindowTest(window, handler =>
+ {
+ var navigation = GetRootNavigationView(handler);
+ var page = Assert.IsType(navigation.Content);
+
+ var btn = Assert.IsAssignableFrom(page.Children[0]);
+
+ Assert.Equal("Yay!", btn.Text);
});
}
+ [Fact]
+ public async Task WindowSupportsEmptyPage_Platform()
+ {
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, handler =>
+ {
+ var navigation = GetRootNavigationView(handler);
+ var page = Assert.IsType(navigation.Content);
+
+ Assert.Null(page.Content);
+ Assert.Empty(page.Children);
+ });
+ }
+
+ void MovePlatformWindow(UI.Xaml.Window window, Rect rect)
+ {
+ var density = window.GetDisplayDensity();
+ window.GetAppWindow().MoveAndResize(new RectInt32(
+ (int)(rect.X * density),
+ (int)(rect.Y * density),
+ (int)(rect.Width * density),
+ (int)(rect.Height * density)));
+ }
+
+ RootNavigationView GetRootNavigationView(IWindowHandler handler)
+ {
+ var rootContainer = handler.PlatformView.Content;
+
+ Assert.NotNull(rootContainer);
+
+ var container = Assert.IsType(rootContainer);
+
+ Assert.NotEmpty(container.Children);
+
+ var root = Assert.IsType(container.Children[0]);
+ var navigation = Assert.IsType(root.Content);
+
+ return navigation;
+ }
+
RootNavigationView GetRootNavigationView(NavigationRootManager navigationRootManager)
{
return (navigationRootManager.RootView as WindowRootView).NavigationViewControl;
}
- Task RunWindowTest(IWindow window, Func action)
+ Task RunWindowStubTest(IWindow window, Func action)
{
return InvokeOnMainThreadAsync(async () =>
{
var scopedContext = new MauiContext(MauiContext.Services);
scopedContext.AddWeakSpecific(window);
+
var mauiContext = scopedContext.MakeScoped(true);
var windowManager = mauiContext.GetNavigationRootManager();
+
windowManager.Connect(window.Content.ToPlatform(mauiContext));
+
var frameworkElement = windowManager.RootView;
await AssertionExtensions.AttachAndRun(frameworkElement, async () =>
@@ -120,5 +220,12 @@ await AssertionExtensions.AttachAndRun(frameworkElement, async () =>
return;
});
}
+
+ Task RunWindowStubTest(IWindow window, Action action) =>
+ RunWindowStubTest(window, handler =>
+ {
+ action(handler);
+ return Task.CompletedTask;
+ });
}
}
\ No newline at end of file
diff --git a/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.cs b/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.cs
index bacc5840920a..3f4587f54b16 100644
--- a/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.cs
+++ b/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.cs
@@ -1,4 +1,7 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Devices;
using Microsoft.Maui.DeviceTests.Stubs;
using Xunit;
@@ -27,6 +30,188 @@ public async Task WindowHasReasonableDisplayDensity()
Assert.Equal(density, req.Result);
Assert.InRange(density, 0.1f, 4f);
}
+#endif
+
+#if MACCATALYST || WINDOWS
+
+ [Fact]
+ public async Task WindowSupportsEmptyPage()
+ {
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, handler =>
+ {
+ Assert.NotNull(handler.PlatformView);
+ });
+ }
+
+ [Theory]
+ [InlineData(150, 300)]
+ [InlineData(200, 300)]
+ [InlineData(500, 500)]
+ [InlineData(1000, 1000)]
+ public async Task MinimumWidthUpdateWindowSize(double min, double expected)
+ {
+ const double initial = 300;
+
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, async handler =>
+ {
+ var platform = handler.PlatformView;
+
+ MovePlatformWindow(platform, new Rect(0, 0, initial, 300));
+
+ Assert.Equal(initial, window.Width);
+
+ window.MinimumWidth = min;
+
+ await Task.Delay(100); // mac catalyst seems to have delays
+
+ Assert.Equal(expected, window.Width);
+ });
+ }
+
+ [Theory]
+ [InlineData(150, 300)]
+ [InlineData(200, 300)]
+ [InlineData(500, 500)]
+ [InlineData(1000, 1000)]
+ public async Task MinimumHeightUpdateWindowSize(double min, double expected)
+ {
+ const double initial = 300;
+
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, async handler =>
+ {
+ var platform = handler.PlatformView;
+
+ MovePlatformWindow(platform, new Rect(0, 0, initial, 300));
+
+ Assert.Equal(initial, window.Height);
+
+ window.MinimumHeight = min;
+
+ await Task.Delay(100); // mac catalyst seems to have delays
+
+ Assert.Equal(expected, window.Height);
+ });
+ }
+
+ [Theory]
+ [InlineData(150, 150)]
+ [InlineData(200, 200)]
+ [InlineData(500, 300)]
+ [InlineData(1000, 300)]
+ public async Task MaximumWidthUpdateWindowSize(double max, double expected)
+ {
+ const double initial = 300;
+
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, async handler =>
+ {
+ var platform = handler.PlatformView;
+
+ MovePlatformWindow(platform, new Rect(0, 0, 300, initial));
+
+ Assert.Equal(initial, window.Width);
+
+ window.MaximumWidth = max;
+
+ await Task.Delay(100); // mac catalyst seems to have delays
+
+ Assert.Equal(expected, window.Width);
+ });
+ }
+
+ [Theory]
+ [InlineData(150, 150)]
+ [InlineData(200, 200)]
+ [InlineData(500, 300)]
+ [InlineData(1000, 300)]
+ public async Task MaximumHeightUpdateWindowSize(double max, double expected)
+ {
+ const double initial = 300;
+
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, async handler =>
+ {
+ var platform = handler.PlatformView;
+
+ MovePlatformWindow(platform, new Rect(0, 0, 300, initial));
+
+ Assert.Equal(initial, window.Height);
+
+ window.MaximumHeight = max;
+
+ await Task.Delay(100); // mac catalyst seems to have delays
+
+ Assert.Equal(expected, window.Height);
+ });
+ }
+
+ Task RunWindowTest(Window window, Func action)
+ {
+ var created = new TaskCompletionSource();
+ var activated = new TaskCompletionSource();
+ var destroying = new TaskCompletionSource();
+
+ window.Created += OnWindowCreated;
+ window.Activated += OnWindowActivated;
+ window.Destroying += OnWindowDestroying;
+
+ var app = Application.Current;
+
+ return InvokeOnMainThreadAsync(async () =>
+ {
+ app.OpenWindow(window);
+
+ await created.Task;
+ await Task.WhenAny(activated.Task, Task.Delay(3000));
+
+ var windowHandler = window.Handler as IWindowHandler;
+ var platformWindow = windowHandler.PlatformView;
+
+#if MACCATALYST
+ var retry = 5;
+ while (!platformWindow.HasNSWindow() && retry-- > 0)
+ {
+ await Task.Delay(100);
+ }
+#endif
+
+ try
+ {
+ await action(windowHandler);
+ }
+ finally
+ {
+ app.CloseWindow(window);
+
+ await destroying.Task;
+ }
+ });
+
+ void OnWindowCreated(object sender, EventArgs e) =>
+ created.TrySetResult();
+
+ void OnWindowActivated(object sender, EventArgs e) =>
+ activated.TrySetResult();
+
+ void OnWindowDestroying(object sender, EventArgs e) =>
+ destroying.TrySetResult();
+ }
+
+ Task RunWindowTest(Window window, Action action) =>
+ RunWindowTest(window, handler =>
+ {
+ action(handler);
+ return Task.CompletedTask;
+ });
+
#endif
}
}
\ No newline at end of file
diff --git a/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.iOS.cs b/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.iOS.cs
new file mode 100644
index 000000000000..54542bc4dc5e
--- /dev/null
+++ b/src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.iOS.cs
@@ -0,0 +1,64 @@
+using System.Threading.Tasks;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Devices;
+using Microsoft.Maui.Graphics;
+using UIKit;
+using Xunit;
+
+namespace Microsoft.Maui.DeviceTests
+{
+ public partial class WindowHandlerTests : HandlerTestBase
+ {
+#if MACCATALYST
+ [Fact]
+ public async Task ContentIsSetInitially()
+ {
+ var window = new Window
+ {
+ Page = new ContentPage
+ {
+ Content = new Button { Text = "Yay!" }
+ }
+ };
+
+ await RunWindowTest(window, handler =>
+ {
+ var root = handler.PlatformView.RootViewController;
+
+ Assert.NotNull(root);
+ var page = Assert.IsType(root);
+
+ Assert.NotNull(page.View);
+ var content = Assert.IsType(root.View.Subviews[0]);
+ var btn = Assert.IsType(content.Subviews[0]);
+
+ Assert.Equal("Yay!", btn.Title(UIControlState.Normal));
+ });
+ }
+
+ [Fact]
+ public async Task WindowSupportsEmptyPage_Platform()
+ {
+ var window = new Window(new ContentPage());
+
+ await RunWindowTest(window, handler =>
+ {
+ var root = handler.PlatformView.RootViewController;
+
+ Assert.NotNull(root);
+ var page = Assert.IsType(root);
+
+ Assert.NotNull(page.View);
+ var content = Assert.IsType(root.View.Subviews[0]);
+
+ Assert.Empty(content.Subviews);
+ });
+ }
+
+ void MovePlatformWindow(UIWindow window, Rect rect)
+ {
+ window.SetFrame(rect, true, false);
+ }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/Core/tests/DeviceTests/Platforms/MacCatalyst/Info.plist b/src/Core/tests/DeviceTests/Platforms/MacCatalyst/Info.plist
index c96dd0a22544..e08aedda8c8b 100644
--- a/src/Core/tests/DeviceTests/Platforms/MacCatalyst/Info.plist
+++ b/src/Core/tests/DeviceTests/Platforms/MacCatalyst/Info.plist
@@ -26,5 +26,22 @@
XSAppIconAssets
Assets.xcassets/appicon.appiconset
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneConfigurationName
+ __MAUI_DEFAULT_SCENE_CONFIGURATION__
+ UISceneDelegateClassName
+ SceneDelegate
+
+
+
+
diff --git a/src/Core/tests/DeviceTests/Platforms/MacCatalyst/SceneDelegate.cs b/src/Core/tests/DeviceTests/Platforms/MacCatalyst/SceneDelegate.cs
new file mode 100644
index 000000000000..cb7685aa5512
--- /dev/null
+++ b/src/Core/tests/DeviceTests/Platforms/MacCatalyst/SceneDelegate.cs
@@ -0,0 +1,8 @@
+using Foundation;
+
+namespace Microsoft.Maui.DeviceTests.MacCatalyst;
+
+[Register("SceneDelegate")]
+public class SceneDelegate : MauiUISceneDelegate
+{
+}
diff --git a/src/Core/tests/DeviceTests/Stubs/WindowStub.cs b/src/Core/tests/DeviceTests/Stubs/WindowStub.cs
index 7a113c44e245..b9905d0924d7 100644
--- a/src/Core/tests/DeviceTests/Stubs/WindowStub.cs
+++ b/src/Core/tests/DeviceTests/Stubs/WindowStub.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.DeviceTests.Stubs
{
@@ -31,46 +32,70 @@ public WindowStub()
public bool IsStopped { get; set; }
public FlowDirection FlowDirection { get; set; }
- public void Activated()
+ public void FrameChanged(Rect frame)
+ {
+ X = frame.X;
+ Y = frame.Y;
+ Width = frame.Width;
+ Height = frame.Height;
+ }
+
+ public double X { get; set; } = double.NaN;
+
+ public double Y { get; set; } = double.NaN;
+
+ public double Width { get; set; } = double.NaN;
+
+ public double Height { get; set; } = double.NaN;
+
+ public double MinimumWidth { get; set; } = double.NaN;
+
+ public double MaximumWidth { get; set; } = double.NaN;
+
+ public double MinimumHeight { get; set; } = double.NaN;
+
+ public double MaximumHeight { get; set; } = double.NaN;
+
+ public virtual void Activated()
{
IsActivated = true;
IsDeactivated = false;
}
- public void Created()
+ public virtual void Created()
{
IsCreated = true;
}
- public void Deactivated()
+ public virtual void Deactivated()
{
IsActivated = false;
IsDeactivated = false;
}
- public void Destroying()
+ public virtual void Destroying()
{
IsDestroyed = true;
IsCreated = false;
}
- public void Resumed()
+ public virtual void Resumed()
{
IsResumed = true;
IsStopped = false;
}
- public void Stopped()
+ public virtual void Stopped()
{
IsStopped = true;
IsResumed = false;
}
- public void Backgrounding(IPersistedState state)
+ public virtual void Backgrounding(IPersistedState state)
{
}
- public bool AddOverlay(IWindowOverlay overlay)
+ public virtual bool AddOverlay(IWindowOverlay overlay)
{
if (overlay is IVisualDiagnosticsOverlay)
return false;
@@ -88,7 +113,7 @@ public bool AddOverlay(IWindowOverlay overlay)
return result;
}
- public bool RemoveOverlay(IWindowOverlay overlay)
+ public virtual bool RemoveOverlay(IWindowOverlay overlay)
{
if (overlay is IVisualDiagnosticsOverlay)
return false;
@@ -100,13 +125,13 @@ public bool RemoveOverlay(IWindowOverlay overlay)
return result;
}
- public bool BackButtonClicked() => true;
+ public virtual bool BackButtonClicked() => true;
public IReadOnlyList GetVisualChildren() => _visualChildren.AsReadOnly();
public IVisualTreeElement GetVisualParent() => this.Parent as IVisualTreeElement;
- public float RequestDisplayDensity() => 1.0f;
+ public virtual float RequestDisplayDensity() => 1.0f;
public virtual void DisplayDensityChanged(float displayDensity) { }
}
diff --git a/src/Essentials/src/Platform/PlatformMethods.uwp.cs b/src/Essentials/src/Platform/PlatformMethods.uwp.cs
index 56f63e8aa5ae..73a5ab97397e 100644
--- a/src/Essentials/src/Platform/PlatformMethods.uwp.cs
+++ b/src/Essentials/src/Platform/PlatformMethods.uwp.cs
@@ -12,6 +12,7 @@ public static class MessageIds
public const int WM_DISPLAYCHANGE = 0x007E;
public const int WM_SETTINGCHANGE = 0x001A;
public const int WM_THEMECHANGE = 0x031A;
+ public const int WM_GETMINMAXINFO = 0x0024;
}
public delegate IntPtr WindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
@@ -76,7 +77,7 @@ public static long GetWindowLongPtr(IntPtr hWnd, WindowLongFlags nIndex)
public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
- public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int width, int height, SetWindowPosFlags uFlags);
+ public static extern bool SetWindowPos(IntPtr hWnd, SpecialWindowHandles hWndInsertAfter, int x, int y, int width, int height, SetWindowPosFlags uFlags);
[DllImport("comctl32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefSubclassProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
@@ -172,12 +173,29 @@ public enum DwmWindowAttribute
}
[StructLayout(LayoutKind.Sequential)]
- struct RECT
+ public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct POINT
+ {
+ public int X;
+ public int Y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MinMaxInfo
+ {
+ public POINT Reserved;
+ public POINT MaxSize;
+ public POINT MaxPosition;
+ public POINT MinTrackSize;
+ public POINT MaxTrackSize;
+ }
}
}
diff --git a/src/Graphics/src/Graphics/Rect.cs b/src/Graphics/src/Graphics/Rect.cs
index e95b22a959f5..b49cc0c8e0b8 100644
--- a/src/Graphics/src/Graphics/Rect.cs
+++ b/src/Graphics/src/Graphics/Rect.cs
@@ -68,7 +68,7 @@ public override int GetHashCode()
public static bool operator ==(Rect r1, Rect r2)
{
- return (r1.Location == r2.Location) && (r1.Size == r2.Size);
+ return r1.Equals(r2);
}
public static bool operator !=(Rect r1, Rect r2)
diff --git a/src/Graphics/src/Graphics/RectF.cs b/src/Graphics/src/Graphics/RectF.cs
index 9ee5b073137b..df1e312601bc 100644
--- a/src/Graphics/src/Graphics/RectF.cs
+++ b/src/Graphics/src/Graphics/RectF.cs
@@ -69,7 +69,7 @@ public override int GetHashCode()
public static bool operator ==(RectF r1, RectF r2)
{
- return (r1.Location == r2.Location) && (r1.Size == r2.Size);
+ return r1.Equals(r2);
}
public static bool operator !=(RectF r1, RectF r2)
diff --git a/src/TestUtils/src/DeviceTests/UINSWindow.iOS.cs b/src/TestUtils/src/DeviceTests/UINSWindow.iOS.cs
new file mode 100644
index 000000000000..5dc12eef3d65
--- /dev/null
+++ b/src/TestUtils/src/DeviceTests/UINSWindow.iOS.cs
@@ -0,0 +1,102 @@
+using Foundation;
+using CoreGraphics;
+using Microsoft.Maui.Graphics;
+using ObjCRuntime;
+using System;
+using System.Runtime.InteropServices;
+using UIKit;
+
+namespace Microsoft.Maui.DeviceTests;
+
+public static class UIWindowExtensions
+{
+ public static void SetFrame(this UIWindow window, Rect frame, bool display = true, bool animate = true)
+ {
+ var nsWindow = UINSWindow.From(window);
+ if (nsWindow is null)
+ throw new InvalidOperationException("Unable to update frame of non-existant window.");
+
+ nsWindow.SetFrame(frame, display, animate);
+ }
+
+ public static bool HasNSWindow(this UIWindow window)
+ {
+ var nsWindow = UINSWindow.From(window);
+ return nsWindow is not null;
+ }
+
+ class UINSWindow
+ {
+ [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
+ static extern void void_objc_msgSend_CGRect_bool_bool(IntPtr receiver, IntPtr selector, CGRect arg1, bool arg2, bool arg3);
+
+ static NativeHandle? nsApplicationHandle;
+ static NativeHandle NSApplicationHandle =>
+ nsApplicationHandle ??= Class.GetHandle("NSApplication");
+
+ static Selector? sharedApplicationSelector;
+ static Selector SharedApplicationSelector =>
+ sharedApplicationSelector ??= new Selector("sharedApplication");
+
+ static Selector? windowsSelector;
+ static Selector WindowsSelector =>
+ windowsSelector ??= new Selector("windows");
+
+ static Selector? uiWindowsSelector;
+ static Selector UIWindowsSelector =>
+ uiWindowsSelector ??= new Selector("uiWindows");
+
+ Selector? setFrameSelector;
+ Selector SetFrameSelector =>
+ setFrameSelector ??= new Selector("setFrame:display:animate:");
+
+ public UINSWindow(NativeHandle handle, UIWindow uiWindow)
+ {
+ Handle = handle;
+ UIWindow = uiWindow;
+ }
+
+ protected NativeHandle Handle { get; }
+
+ public UIWindow UIWindow { get; }
+
+ public void SetFrame(CGRect frame, bool display = true, bool animate = true)
+ {
+ var screenHeight = UIWindow.Screen.Bounds.Height;
+ frame = new CGRect(
+ frame.X / 1.3,
+ screenHeight - (frame.Y / 1.3),
+ frame.Width / 1.3,
+ frame.Height / 1.3);
+
+ void_objc_msgSend_CGRect_bool_bool(Handle.Handle, SetFrameSelector.Handle, frame, display, animate);
+ }
+
+ internal static UINSWindow? From(UIWindow uiWindow)
+ {
+ var nsapp = Runtime.GetNSObject(NSApplicationHandle);
+ if (nsapp is null)
+ return null;
+
+ var sharedApp = nsapp.PerformSelector(SharedApplicationSelector);
+ var windows = sharedApp.PerformSelector(WindowsSelector) as NSArray;
+
+ for (nuint i = 0; i < windows!.Count; i++)
+ {
+ var nswin = windows.GetItem(i);
+
+ var uiwindows = nswin.PerformSelector(UIWindowsSelector) as NSArray;
+
+ for (nuint j = 0; j < uiwindows!.Count; j++)
+ {
+ var uiwin = uiwindows.GetItem(j);
+
+ if (uiwin.Handle == uiWindow.Handle)
+ return new UINSWindow(nswin.Handle, uiWindow);
+ }
+ }
+
+ return null;
+ }
+ }
+}