dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.05k stars 1.73k forks source link

Ability to set initial window size and position and restore previous values #7592

Open Shrp77 opened 2 years ago

Shrp77 commented 2 years ago

Description

I wish to be able to define a default starting size and position for the MAUI application and to restore the window position and size the next time the application is launched.

While I understand the paradigm of starting MAUI apps as full-screen (or close to full screen), it is very impractical for users to have ultra-wide monitors (in my case a 49" 5440x1440 monitor); I literally have to turn my head to change from the left side to the right side of the monitor.

I have a work-around for the initial window size and position* (except for not being able to determine the screen size, so I cannot do bounds checking to make sure the window is wholly within the screen for different resolutions / monitor sizes) but would prefer to have official support, cross platform to MacOS, for this functionality.

Public API Changes

int initialWidth = 1024;
int initialHeight = 726;

Screen primary = Screen.GetPrimaryScreen(); // New API
RectInt32 sizeAndPosition = new RectInt32(
   primary.Width/2 - initialWidth/2,
   primary.Height/2 - initialHeight/2,
   initialWidth,
   initialHeight);
Window window = new Window(new SomePage(), sizeAndPosition); // New API

Intended Use-Case

My app has two distinct modes of operation; Full mode for Desktop environments (Windows / MacOS) and Player for mobile devices (Android / iOS). On desktop environments (Windows / MacOS), full screen is not a desired initial state for the application.

If the user has resized and positioned the window in a specific location of the screen - as long as that position + size is still valid the application should re-launch to that position and size.

Dbquity commented 2 years ago

I am not sure we need API changes to improve significantly :-) IMHO a very good first, hardcoded solution could be to let the end user resize and move the window and then restore to that size and position the next time the app opens.

Shrp77 commented 2 years ago

Granted - as long as the system is able to do bounds check to validate that the restored position of the window falls within a valid range and doesn't restore to an off-screen location.

Example:

In this case, it would be perfectly acceptable for the app to be opened in the valid screen, then either get its "default sizing" (behavior we see today) or retain the size it had before if the size can be contained within the screen bounds (minus the task bar).

mattleibow commented 2 years ago

I started on this some time ago https://github.com/dotnet/maui/pull/4942

mattleibow commented 1 year ago

I see this issue was closed incorrectly as this was a new automatic feature rather than the support for a manual feature.

mattleibow commented 1 year ago

One thing I noticed today, mac catalyst already save window size and position. So this is probably more just for windows.

Redth commented 1 year ago

Given there's now API's to set the window size/position on windows, you can definitely handle saving and restoring this state yourself as a workaround.

DanJBower commented 7 months ago

Given there's now API's to set the window size/position on windows, you can definitely handle saving and restoring this state yourself as a workaround.

Whilst it would be nice if it worked out the box. If anyone else needs it, I've been using this workaround

#if WINDOWS
using Microsoft.Maui.Platform;
using Microsoft.UI.Windowing;
using Windows.Graphics;
#endif

namespace Sample;

public partial class App
{
    public App()
    {
        InitializeComponent();

        MainPage = new MainPage();
    }

#if WINDOWS
    private const string LastWidthPropertyKey = "windows_last_window_width";
    private const string LastHeightPropertyKey = "windows_last_window_height";
    private const string LastXPropertyKey = "windows_last_window_x";
    private const string LastYPropertyKey = "windows_last_window_y";

    protected override Window CreateWindow(IActivationState? activationState)
    {
        var window = base.CreateWindow(activationState);
        AppWindow appWindow = null!;

        window.Created += (_, _) =>
        {
            var nativeWindow = (MauiWinUIWindow)window.Handler!.PlatformView!;
            appWindow = nativeWindow.GetAppWindow()!;

            if (Preferences.Default.ContainsKey(LastWidthPropertyKey) &&
                Preferences.Default.ContainsKey(LastHeightPropertyKey))
            {
                window.Width = Preferences.Default.Get(LastWidthPropertyKey, -1.0);
                window.Height = Preferences.Default.Get(LastHeightPropertyKey, -1.0);
            }

            if (Preferences.Default.ContainsKey(LastXPropertyKey) &&
                Preferences.Default.ContainsKey(LastYPropertyKey))
            {
                // Using appWindow.Move as setting window.X and window.Y was not working properly
                // with monitors where scaling wasn't 100%.
                appWindow.Move(new PointInt32(
                    Preferences.Default.Get(LastXPropertyKey, 0),
                    Preferences.Default.Get(LastYPropertyKey, 0)
                ));
            }
        };

        window.Destroying += (_, _) =>
        {
            Preferences.Default.Set(LastWidthPropertyKey, window.Width);
            Preferences.Default.Set(LastHeightPropertyKey, window.Height);
            Preferences.Default.Set(LastXPropertyKey, appWindow.Position.X);
            Preferences.Default.Set(LastYPropertyKey, appWindow.Position.Y);
        };

        return window;
    }
#endif
}
iascience commented 4 months ago

Given there's now API's to set the window size/position on windows, you can definitely handle saving and restoring this state yourself as a workaround.

This is fine until the layout has changed, e.g. the situation described earlier where an external monitor has been disconnected. My current workaround is to use EnumDisplayMonitors and GetMonitorInfo through P/Invoke, which works fine but obviously only on Windows.

MartyIX commented 1 week ago

There is also @dotMorten's WinUIEx and it provides this feature. See the MAUI sample and particularly the configuration. Note that the feature works for Windows packaged apps only.

Useful links

dotMorten commented 1 week ago

@MartyIX more specifically this part of the doc: https://dotmorten.github.io/WinUIEx/concepts/Maui.html#perform-operations-when-windows-are-created