diff --git a/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/commandbar/CommandBarIntegrationTests.cs b/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/commandbar/CommandBarIntegrationTests.cs index 03d4891aec76..41f89ae446f8 100644 --- a/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/commandbar/CommandBarIntegrationTests.cs +++ b/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/commandbar/CommandBarIntegrationTests.cs @@ -2584,7 +2584,7 @@ public async Task ValidateFootprint() #if __IOS__ await RunOnUIThread(() => { - expectedCommandBarWidth = NativeWindowWrapper.Instance.GetWindowSize().Width; + expectedCommandBarWidth = WindowHelper.XamlRoot.HostWindow!.NativeWindowWrapper!.GetWindowSize().Width; }); #endif double expectedCommandBarCompactClosedHeight = 48; diff --git a/src/Uno.UI/UI/Xaml/Application.iOS.cs b/src/Uno.UI/UI/Xaml/Application.iOS.cs index 73d238fc6812..389dda46a8b5 100644 --- a/src/Uno.UI/UI/Xaml/Application.iOS.cs +++ b/src/Uno.UI/UI/Xaml/Application.iOS.cs @@ -30,8 +30,6 @@ public partial class Application : UIApplicationDelegate partial void InitializePartial() { SetCurrentLanguage(); - - SubscribeBackgroundNotifications(); } public Application(NativeHandle handle) : base(handle) @@ -189,47 +187,6 @@ private bool TryGetUserActivityFromLaunchOptions(NSDictionary launchOptions, out return userActivity != null; } - private void SubscribeBackgroundNotifications() - { - if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0)) - { - NSNotificationCenter.DefaultCenter.AddObserver(UIScene.DidEnterBackgroundNotification, OnEnteredBackground); - NSNotificationCenter.DefaultCenter.AddObserver(UIScene.WillEnterForegroundNotification, OnLeavingBackground); - NSNotificationCenter.DefaultCenter.AddObserver(UIScene.DidActivateNotification, OnActivated); - NSNotificationCenter.DefaultCenter.AddObserver(UIScene.WillDeactivateNotification, OnDeactivated); - } - else - { - NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidEnterBackgroundNotification, OnEnteredBackground); - NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.WillEnterForegroundNotification, OnLeavingBackground); - NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidBecomeActiveNotification, OnActivated); - NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.WillResignActiveNotification, OnDeactivated); - } - } - - private void OnEnteredBackground(NSNotification notification) - { - NativeWindowWrapper.Instance.OnNativeVisibilityChanged(false); - - RaiseEnteredBackground(() => RaiseSuspending()); - } - - private void OnLeavingBackground(NSNotification notification) - { - RaiseResuming(); - RaiseLeavingBackground(() => NativeWindowWrapper.Instance.OnNativeVisibilityChanged(true)); - } - - private void OnActivated(NSNotification notification) - { - NativeWindowWrapper.Instance.OnNativeActivated(CoreWindowActivationState.CodeActivated); - } - - private void OnDeactivated(NSNotification notification) - { - NativeWindowWrapper.Instance.OnNativeActivated(CoreWindowActivationState.Deactivated); - } - private void SetCurrentLanguage() { // net6.0-iOS does not automatically set the thread and culture info diff --git a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs index 3bc442f647d0..ea5cdca86868 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs @@ -397,6 +397,7 @@ private protected virtual void ShowAtCore(FrameworkElement placementTarget, Flyo XamlRoot = placementTarget?.XamlRoot; _popup.XamlRoot = XamlRoot; _popup.PlacementTarget = placementTarget; + UpdatePopupPanelSizePartial(); if (showOptions != null) { @@ -483,6 +484,8 @@ private protected virtual void ShowAtCore(FrameworkElement placementTarget, Flyo }); } + partial void UpdatePopupPanelSizePartial(); + private void SetTargetPosition(Point targetPoint) { m_isTargetPositionSet = true; @@ -542,6 +545,7 @@ protected internal virtual void Open() { _popup.XamlRoot = XamlRoot; } + UpdatePopupPanelSizePartial(); _popup.IsOpen = true; diff --git a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.iOSmacOS.cs b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.iOSmacOS.cs index 9a85eaae1c34..ac36dd6c3950 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.iOSmacOS.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.iOSmacOS.cs @@ -35,7 +35,14 @@ partial void InitializePopupPanelPartial() NSViewResizingMask.MinYMargin | NSViewResizingMask.MaxYMargin, #endif - Frame = new CGRect(CGPoint.Empty, NativeWindowWrapper.Instance.GetWindowSize()) }; } + + partial void UpdatePopupPanelSizePartial() + { + if (XamlRoot?.HostWindow is { } window) + { + _popup.PopupPanel.Frame = new CGRect(CGPoint.Empty, window.NativeWindowWrapper.GetWindowSize()); + } + } } diff --git a/src/Uno.UI/UI/Xaml/Controls/TimePicker/NativeTimePickerFlyout.iOS.cs b/src/Uno.UI/UI/Xaml/Controls/TimePicker/NativeTimePickerFlyout.iOS.cs index fb0a8ea6d400..705b24dbff3b 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TimePicker/NativeTimePickerFlyout.iOS.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TimePicker/NativeTimePickerFlyout.iOS.cs @@ -30,7 +30,6 @@ protected override void InitializePopupPanel() Visibility = Visibility.Collapsed, Background = SolidColorBrushHelper.Transparent, AutoresizingMask = UIViewAutoresizing.All, - Frame = new CGRect(CGPoint.Empty, NativeWindowWrapper.Instance.GetWindowSize()) }; } diff --git a/src/Uno.UI/UI/Xaml/Internal/ContentManager/ContentManager.iOS.cs b/src/Uno.UI/UI/Xaml/Internal/ContentManager/ContentManager.iOS.cs index d25a6fa9c911..af3356127626 100644 --- a/src/Uno.UI/UI/Xaml/Internal/ContentManager/ContentManager.iOS.cs +++ b/src/Uno.UI/UI/Xaml/Internal/ContentManager/ContentManager.iOS.cs @@ -11,11 +11,16 @@ partial class ContentManager { static partial void AttachToWindowPlatform(UIElement rootElement, Microsoft.UI.Xaml.Window window) { + if (window.NativeWindowWrapper is not NativeWindowWrapper nativeWindowWrapper) + { + throw new InvalidOperationException("The window must be initialized before attaching the root element."); + } + if (rootElement.Superview is null) { - NativeWindowWrapper.Instance.MainController.View!.AddSubview(rootElement); + nativeWindowWrapper.MainController.View!.AddSubview(rootElement); } - rootElement.Frame = NativeWindowWrapper.Instance.MainController.View!.Bounds; + rootElement.Frame = nativeWindowWrapper.MainController.View!.Bounds; rootElement.AutoresizingMask = UIViewAutoresizing.All; } } diff --git a/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs b/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs index b604073549b5..6010bde18180 100644 --- a/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs +++ b/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs @@ -52,7 +52,7 @@ public BaseWindowImplementation(Window window) protected Window Window { get; } - protected INativeWindowWrapper? NativeWindowWrapper { get; private set; } + public INativeWindowWrapper? NativeWindowWrapper { get; private set; } public abstract CoreWindow? CoreWindow { get; } diff --git a/src/Uno.UI/UI/Xaml/Window/Implementations/IWindowImplementation.cs b/src/Uno.UI/UI/Xaml/Window/Implementations/IWindowImplementation.cs index 5276d45262af..1592524d71cf 100644 --- a/src/Uno.UI/UI/Xaml/Window/Implementations/IWindowImplementation.cs +++ b/src/Uno.UI/UI/Xaml/Window/Implementations/IWindowImplementation.cs @@ -12,6 +12,8 @@ namespace Uno.UI.Xaml.Controls; internal interface IWindowImplementation { + INativeWindowWrapper? NativeWindowWrapper { get; } + bool Visible { get; } string Title { get; set; } diff --git a/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.iOS.cs b/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.iOS.cs new file mode 100644 index 000000000000..cec1d2d078c2 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.iOS.cs @@ -0,0 +1,21 @@ +#nullable enable +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.UI.Xaml; + +namespace Uno.UI.Xaml.Controls; + +internal partial class NativeWindowFactory +{ + public static bool SupportsClosingCancellation => false; + + public static bool SupportsMultipleWindows => false; + + private static INativeWindowWrapper? CreateWindowPlatform(Microsoft.UI.Xaml.Window window, XamlRoot xamlRoot) => + new NativeWindowWrapper(window, xamlRoot); +} diff --git a/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.others.cs b/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.others.cs index 1e337959ff9f..4a9b09eca1d6 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.others.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/Factory/NativeWindowFactory.others.cs @@ -1,5 +1,5 @@ #nullable enable -#if !__SKIA__ +#if !__SKIA__ && !__IOS__ using System; using Uno.Foundation.Extensibility; diff --git a/src/Uno.UI/UI/Xaml/Window/Native/INativeWindowWrapper.cs b/src/Uno.UI/UI/Xaml/Window/Native/INativeWindowWrapper.cs index 75856c5f0574..61f136086294 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/INativeWindowWrapper.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/INativeWindowWrapper.cs @@ -41,4 +41,8 @@ internal interface INativeWindowWrapper : INativeAppWindow void Close(); void ExtendContentIntoTitleBar(bool extend); + +#if __IOS__ || __MACOS__ + Size GetWindowSize(); +#endif } diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs index 94be61b1230e..f802c384cd8b 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs @@ -17,7 +17,7 @@ namespace Uno.UI.Xaml.Controls; -internal class NativeWindowWrapper : NativeWindowWrapperBase +internal class NativeWindowWrapper : NativeWindowWrapperBase, INativeWindowWrapper { private static readonly Lazy _instance = new(() => new NativeWindowWrapper()); diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.iOS.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.iOS.cs index aea26cb12bc0..abf0b4fcc037 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.iOS.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.iOS.cs @@ -9,29 +9,33 @@ using Windows.UI.Core; using Windows.UI.ViewManagement; using Windows.Graphics; +using MUXWindow = Microsoft.UI.Xaml.Window; +using NativeWindow = Uno.UI.Controls.Window; +using Microsoft.UI.Xaml; +using static Microsoft.UI.Xaml.Controls.Primitives.LoopingSelectorItem; namespace Uno.UI.Xaml.Controls; -internal class NativeWindowWrapper : NativeWindowWrapperBase +internal class NativeWindowWrapper : NativeWindowWrapperBase, INativeWindowWrapper { - private static readonly Lazy _instance = new(() => new NativeWindowWrapper()); - - private Uno.UI.Controls.Window _nativeWindow; + private NativeWindow _nativeWindow; private RootViewController _mainController; private NSObject _orientationRegistration; private readonly DisplayInformation _displayInformation; - public NativeWindowWrapper() + public NativeWindowWrapper(MUXWindow window, XamlRoot xamlRoot) { - _nativeWindow = new Uno.UI.Controls.Window(); + _nativeWindow = new NativeWindow(); - _mainController = Microsoft.UI.Xaml.Window.ViewControllerGenerator?.Invoke() ?? new RootViewController(); + _mainController = MUXWindow.ViewControllerGenerator?.Invoke() ?? new RootViewController(); _mainController.View.BackgroundColor = UIColor.Clear; _mainController.NavigationBarHidden = true; ObserveOrientationAndSize(); + SubscribeBackgroundNotifications(); + #if __MACCATALYST__ _nativeWindow.SetOwner(CoreWindow.GetForCurrentThreadSafe()); #endif @@ -41,9 +45,7 @@ public NativeWindowWrapper() DispatchDpiChanged(); } - public override Uno.UI.Controls.Window NativeWindow => _nativeWindow; - - internal static NativeWindowWrapper Instance => _instance.Value; + public override NativeWindow NativeWindow => _nativeWindow; private void DispatchDpiChanged() => RasterizationScale = (float)_displayInformation.RawPixelsPerViewPixel; @@ -58,8 +60,6 @@ protected override void ShowCore() internal void OnNativeVisibilityChanged(bool visible) => IsVisible = visible; - internal void OnNativeActivated(CoreWindowActivationState state) => ActivationState = state; - internal void OnNativeClosed() => RaiseClosing(); // TODO: Handle closing cancellation when multiwindow is supported #13847 internal void RaiseNativeSizeChanged() @@ -99,16 +99,16 @@ private void ObserveOrientationAndSize() RaiseNativeSizeChanged(); } - internal Size GetWindowSize() + public override Size GetWindowSize() { var nativeFrame = NativeWindow?.Frame ?? CGRect.Empty; return new Size(nativeFrame.Width, nativeFrame.Height); } - private void SetVisibleBounds(UIKit.UIWindow keyWindow, Windows.Foundation.Size windowSize) + private void SetVisibleBounds(UIWindow keyWindow, Size windowSize) { - var windowBounds = new Windows.Foundation.Rect(default, windowSize); + var windowBounds = new Rect(default, windowSize); var inset = UseSafeAreaInsets ? keyWindow.SafeAreaInsets @@ -123,7 +123,7 @@ private void SetVisibleBounds(UIKit.UIWindow keyWindow, Windows.Foundation.Size inset.Top = (nfloat)Math.Max(inset.Top, statusBarHeight); - var newVisibleBounds = new Windows.Foundation.Rect( + var newVisibleBounds = new Rect( x: windowBounds.Left + inset.Left, y: windowBounds.Top + inset.Top, width: windowBounds.Width - inset.Right - inset.Left, @@ -141,4 +141,39 @@ protected override IDisposable ApplyFullScreenPresenter() UIApplication.SharedApplication.StatusBarHidden = true; return Disposable.Create(() => UIApplication.SharedApplication.StatusBarHidden = false); } + + private void SubscribeBackgroundNotifications() + { + if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0)) + { + NSNotificationCenter.DefaultCenter.AddObserver(UIScene.DidEnterBackgroundNotification, OnEnteredBackground); + NSNotificationCenter.DefaultCenter.AddObserver(UIScene.WillEnterForegroundNotification, OnLeavingBackground); + NSNotificationCenter.DefaultCenter.AddObserver(UIScene.DidActivateNotification, OnActivated); + NSNotificationCenter.DefaultCenter.AddObserver(UIScene.WillDeactivateNotification, OnDeactivated); + } + else + { + NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidEnterBackgroundNotification, OnEnteredBackground); + NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.WillEnterForegroundNotification, OnLeavingBackground); + NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidBecomeActiveNotification, OnActivated); + NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.WillResignActiveNotification, OnDeactivated); + } + } + + private void OnEnteredBackground(NSNotification notification) + { + OnNativeVisibilityChanged(false); + + Application.Current.RaiseEnteredBackground(() => Application.Current.RaiseSuspending()); + } + + private void OnLeavingBackground(NSNotification notification) + { + Application.Current.RaiseResuming(); + Application.Current.RaiseLeavingBackground(() => OnNativeVisibilityChanged(true)); + } + + private void OnActivated(NSNotification notification) => ActivationState = CoreWindowActivationState.CodeActivated; + + private void OnDeactivated(NSNotification notification) => ActivationState = CoreWindowActivationState.Deactivated; } diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.macOS.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.macOS.cs index ad81070260b4..3c9ad8f58902 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.macOS.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.macOS.cs @@ -20,7 +20,7 @@ namespace Uno.UI.Xaml.Controls; -internal class NativeWindowWrapper : NativeWindowWrapperBase +internal class NativeWindowWrapper : NativeWindowWrapperBase, INativeWindowWrapper { private static readonly Lazy _instance = new(() => new NativeWindowWrapper()); diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.reference.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.reference.cs index 37b01cc0ef6b..37451e9b423e 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.reference.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.reference.cs @@ -2,7 +2,7 @@ namespace Uno.UI.Xaml.Controls; -internal partial class NativeWindowWrapper : NativeWindowWrapperBase +internal partial class NativeWindowWrapper : NativeWindowWrapperBase, INativeWindowWrapper { private static readonly Lazy _instance = new(() => new NativeWindowWrapper()); diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.unittests.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.unittests.cs index ac2cc22645ee..2c62d30958a6 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.unittests.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.unittests.cs @@ -5,7 +5,7 @@ namespace Uno.UI.Xaml.Controls; -internal partial class NativeWindowWrapper : NativeWindowWrapperBase +internal partial class NativeWindowWrapper : NativeWindowWrapperBase, INativeWindowWrapper { private static readonly Lazy _instance = new(() => new NativeWindowWrapper()); diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.wasm.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.wasm.cs index d25564f28356..b19110ea3348 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.wasm.cs @@ -8,7 +8,7 @@ namespace Uno.UI.Xaml.Controls; -internal partial class NativeWindowWrapper : NativeWindowWrapperBase +internal partial class NativeWindowWrapper : NativeWindowWrapperBase, INativeWindowWrapper { private static readonly Lazy _instance = new(() => new NativeWindowWrapper()); diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs index 6c06d0e54a8c..e217dbba15ba 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs @@ -273,4 +273,8 @@ public virtual void Resize(SizeInt32 size) public void Destroy() { } public void Hide() { } + +#if __IOS__ || __MACOS__ + public abstract Size GetWindowSize(); +#endif } diff --git a/src/Uno.UI/UI/Xaml/Window/Window.cs b/src/Uno.UI/UI/Xaml/Window/Window.cs index 26a252038f5b..f4b066ff3d8e 100644 --- a/src/Uno.UI/UI/Xaml/Window/Window.cs +++ b/src/Uno.UI/UI/Xaml/Window/Window.cs @@ -102,6 +102,8 @@ internal Window(WindowType windowType) global::Windows.Graphics.Display.DisplayInformation.GetOrCreateForWindowId(AppWindow.Id); } + internal INativeWindowWrapper? NativeWindowWrapper => _windowImplementation.NativeWindowWrapper; + internal static Window GetFromAppWindow(AppWindow appWindow) { if (!_appWindowMap.TryGetValue(appWindow, out var window))