diff --git a/src/SamplesApp/UITests.Shared/Microsoft_UI_Windowing/AppWindowPositionAndSize.xaml.cs b/src/SamplesApp/UITests.Shared/Microsoft_UI_Windowing/AppWindowPositionAndSize.xaml.cs index 46f8a78a41e0..46c5e1ea03e7 100644 --- a/src/SamplesApp/UITests.Shared/Microsoft_UI_Windowing/AppWindowPositionAndSize.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Microsoft_UI_Windowing/AppWindowPositionAndSize.xaml.cs @@ -30,7 +30,10 @@ public AppWindowPositionAndSize() private void AppWindowPositionAndSize_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args) { ViewModel = args.NewValue as AppWindowPositionAndSizeViewModel; - ViewModel.XamlRoot = XamlRoot; + if (ViewModel is not null) + { + ViewModel.XamlRoot = XamlRoot; + } } } diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/UI/FrameBufferWindowWrapper.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/UI/FrameBufferWindowWrapper.cs index c16fcb23ec22..d1dd163be3da 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/UI/FrameBufferWindowWrapper.cs +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/UI/FrameBufferWindowWrapper.cs @@ -29,7 +29,7 @@ internal void RaiseNativeSizeChanged(Size newWindowSize) VisibleBounds = new Rect(default, newWindowSize); } - internal void OnNativeVisibilityChanged(bool visible) => Visible = visible; + internal void OnNativeVisibilityChanged(bool visible) => IsVisible = visible; internal void OnNativeActivated(CoreWindowActivationState state) => ActivationState = state; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/WpfWindowWrapper.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/WpfWindowWrapper.cs index 0cad12f798c8..c3e931a0c6c5 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/WpfWindowWrapper.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/WpfWindowWrapper.cs @@ -32,7 +32,21 @@ public WpfWindowWrapper(UnoWpfWindow wpfWindow, XamlRoot xamlRoot) : base(xamlRo _wpfWindow.StateChanged += OnNativeStateChanged; _wpfWindow.Host.SizeChanged += (_, e) => OnHostSizeChanged(e.NewSize); OnHostSizeChanged(new Size(_wpfWindow.Width, _wpfWindow.Height)); + _wpfWindow.LocationChanged += OnNativeLocationChanged; + _wpfWindow.SizeChanged += OnNativeSizeChanged; + UpdateSizeFromNative(); + UpdatePositionFromNative(); } + + private void OnNativeSizeChanged(object sender, SizeChangedEventArgs e) => UpdateSizeFromNative(); + + private void UpdateSizeFromNative() => + Size = new() { Width = (int)_wpfWindow.Width, Height = (int)_wpfWindow.Height }; + + private void OnNativeLocationChanged(object? sender, EventArgs e) => UpdatePositionFromNative(); + + private void UpdatePositionFromNative() => + Position = new() { X = (int)_wpfWindow.Left, Y = (int)_wpfWindow.Top }; private void OnNativeStateChanged(object? sender, EventArgs e) => UpdateIsVisible(); @@ -50,6 +64,7 @@ protected override void ShowCore() { RasterizationScale = (float)VisualTreeHelper.GetDpi(_wpfWindow.Host).DpiScaleX; _wpfWindow.Show(); + UpdatePositionFromNative(); } public override void Activate() => _wpfWindow.Activate(); @@ -111,11 +126,11 @@ private void UpdateIsVisible() if (isVisible) { - WinUIApplication.Current?.RaiseLeavingBackground(() => Visible = isVisible); + WinUIApplication.Current?.RaiseLeavingBackground(() => IsVisible = isVisible); } else { - Visible = isVisible; + IsVisible = isVisible; WinUIApplication.Current?.RaiseEnteredBackground(null); } } @@ -144,4 +159,16 @@ protected override IDisposable ApplyOverlappedPresenter(OverlappedPresenter pres presenter.SetNative(new NativeOverlappedPresenter(_wpfWindow)); return Disposable.Create(() => presenter.SetNative(null)); } + + public override void Move(PointInt32 position) + { + _wpfWindow.Left = position.X; + _wpfWindow.Top = position.Y; + } + + public override void Resize(SizeInt32 size) + { + _wpfWindow.Width = size.Width; + _wpfWindow.Height = size.Height; + } } diff --git a/src/Uno.UI.Runtime.Skia.X11/X11WindowWrapper.cs b/src/Uno.UI.Runtime.Skia.X11/X11WindowWrapper.cs index 00036d2e8168..3468e0120c41 100644 --- a/src/Uno.UI.Runtime.Skia.X11/X11WindowWrapper.cs +++ b/src/Uno.UI.Runtime.Skia.X11/X11WindowWrapper.cs @@ -122,7 +122,7 @@ private void OnWindowClosing() private void OnNativeActivated(bool focused) => ActivationState = focused ? CoreWindowActivationState.PointerActivated : CoreWindowActivationState.Deactivated; - private void OnNativeVisibilityChanged(bool visible) => Visible = visible; + private void OnNativeVisibilityChanged(bool visible) => IsVisible = visible; protected override void ShowCore() { diff --git a/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs b/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs index 591961b9a2bc..ec8f953430a6 100644 --- a/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs +++ b/src/Uno.UI/UI/Xaml/Window/Implementations/BaseWindowImplementation.cs @@ -48,7 +48,7 @@ public BaseWindowImplementation(Window window) public abstract CoreWindow? CoreWindow { get; } - public bool Visible => NativeWindowWrapper?.Visible ?? false; + public bool Visible => NativeWindowWrapper?.IsVisible ?? false; public abstract UIElement? Content { get; set; } diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs index 2084171813a9..e6b88146f543 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapperBase.cs @@ -9,7 +9,7 @@ using Windows.Foundation; using Windows.UI.Core; using Windows.Graphics; -using Microsoft.UI.Dispatching; +using Windows.UI.Core; namespace Uno.UI.Xaml.Controls; @@ -22,6 +22,8 @@ internal abstract class NativeWindowWrapperBase : INativeWindowWrapper private Rect _bounds; private Rect _visibleBounds; private bool _visible; + private PointInt32 _position; + private SizeInt32 _size; private string _title = ""; private CoreWindowActivationState _activationState; private XamlRoot? _xamlRoot; @@ -86,7 +88,7 @@ public CoreWindowActivationState ActivationState } } - public bool Visible + public bool IsVisible { get => _visible; set @@ -130,11 +132,31 @@ public virtual string Title } } - public bool IsVisible => throw new NotImplementedException(); - - public PointInt32 Position => throw new NotImplementedException(); + public PointInt32 Position + { + get => _position; + set + { + if (!_position.Equals(value)) + { + _position = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Position))); + } + } + } - public SizeInt32 Size => throw new NotImplementedException(); + public SizeInt32 Size + { + get => _size; + set + { + if (!_size.Equals(value)) + { + _size = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Size))); + } + } + } public SizeInt32 ClientSize => throw new NotImplementedException(); @@ -147,6 +169,7 @@ public virtual string Title public event EventHandler? Closing; public event EventHandler? Closed; public event EventHandler? Shown; + public event PropertyChangedEventHandler? PropertyChanged; public virtual void Activate() { } @@ -202,9 +225,15 @@ private void RaiseContentIslandStateChanged(ContentIslandStateChangedEventArgs a { XamlRoot?.VisualTree.ContentRoot.CompositionContent?.RaiseStateChanged(args); } + public virtual void Move(PointInt32 position) + { + } + + public virtual void Resize(SizeInt32 size) + { + } + public void Destroy() => throw new NotImplementedException(); public void Hide() => throw new NotImplementedException(); - public void Move(PointInt32 position) => throw new NotImplementedException(); - public void Resize(SizeInt32 size) => throw new NotImplementedException(); public void Show(bool activateWindow) => throw new NotImplementedException(); } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Microsoft.UI.Windowing/AppWindow.cs b/src/Uno.UWP/Generated/3.0.0.0/Microsoft.UI.Windowing/AppWindow.cs index d3dd8a2ffcbf..98e62f3e965c 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Microsoft.UI.Windowing/AppWindow.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Microsoft.UI.Windowing/AppWindow.cs @@ -111,7 +111,7 @@ public void Hide() global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Microsoft.UI.Windowing.AppWindow", "void AppWindow.Hide()"); } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public void Move(global::Windows.Graphics.PointInt32 position) { @@ -132,7 +132,7 @@ public void MoveAndResize(global::Windows.Graphics.RectInt32 rect, global::Micro global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Microsoft.UI.Windowing.AppWindow", "void AppWindow.MoveAndResize(RectInt32 rect, DisplayArea displayarea)"); } #endif -#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public void Resize(global::Windows.Graphics.SizeInt32 size) { diff --git a/src/Uno.UWP/Microsoft/UI/Windowing/AppWindow.cs b/src/Uno.UWP/Microsoft/UI/Windowing/AppWindow.cs index b87d86bc8589..84d4298639bc 100644 --- a/src/Uno.UWP/Microsoft/UI/Windowing/AppWindow.cs +++ b/src/Uno.UWP/Microsoft/UI/Windowing/AppWindow.cs @@ -2,12 +2,12 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Threading; -using Windows.Foundation; +using Microsoft.UI.Dispatching; using Microsoft.UI.Windowing.Native; +using Windows.Foundation; +using Windows.Graphics; using Windows.UI.ViewManagement; using MUXWindowId = Microsoft.UI.WindowId; -using Windows.Graphics; -using Microsoft.UI.Dispatching; namespace Microsoft.UI.Windowing; @@ -107,6 +107,7 @@ internal void SetNativeWindow(INativeAppWindow nativeAppWindow) } _nativeAppWindow = nativeAppWindow; + _nativeAppWindow.PropertyChanged += OnNativeAppWindowPropertyChanged; if (string.IsNullOrWhiteSpace(_nativeAppWindow.Title) && !string.IsNullOrWhiteSpace(_titleCache)) { @@ -120,6 +121,18 @@ internal void SetNativeWindow(INativeAppWindow nativeAppWindow) SetPresenter(AppWindowPresenterKind.Default); } + private void OnNativeAppWindowPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(INativeAppWindow.Position)) + { + OnAppWindowChanged(new AppWindowChangedEventArgs() { DidPositionChange = true }); + } + else if (e.PropertyName == nameof(INativeAppWindow.Size)) + { + OnAppWindowChanged(new AppWindowChangedEventArgs() { DidSizeChange = true }); + } + } + public event TypedEventHandler Closing; internal static MUXWindowId MainWindowId { get; } = new(1); @@ -136,6 +149,10 @@ public static AppWindow GetFromWindowId(MUXWindowId windowId) internal static bool TryGetFromWindowId(MUXWindowId windowId, [NotNullWhen(true)] out AppWindow appWindow) => _windowIdMap.TryGetValue(windowId, out appWindow); + + public void Move(PointInt32 position) => _nativeAppWindow.Move(position); + + public void Resize(SizeInt32 size) => _nativeAppWindow.Resize(size); public void SetPresenter(AppWindowPresenter appWindowPresenter) { @@ -174,4 +191,6 @@ public void SetPresenter(AppWindowPresenterKind appWindowPresenterKind) } internal void RaiseClosing(AppWindowClosingEventArgs args) => Closing?.Invoke(this, args); + + internal void OnAppWindowChanged(AppWindowChangedEventArgs args) => Changed?.Invoke(this, args); } diff --git a/src/Uno.UWP/Microsoft/UI/Windowing/Native/INativeAppWindow.cs b/src/Uno.UWP/Microsoft/UI/Windowing/Native/INativeAppWindow.cs index 54a1b5bff619..c3a9e9186f13 100644 --- a/src/Uno.UWP/Microsoft/UI/Windowing/Native/INativeAppWindow.cs +++ b/src/Uno.UWP/Microsoft/UI/Windowing/Native/INativeAppWindow.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -23,6 +24,8 @@ internal interface INativeAppWindow DispatcherQueue DispatcherQueue { get; } + event PropertyChangedEventHandler PropertyChanged; + void Destroy(); void Hide();