MAUI .NET Установка размера окна

Как установить размер окна в MAUI?

Справочная информация: меня интересует только Windows для этого приложения — я выбрал MAUI, чтобы использовать Blazor для настольного приложения. По какой-то причине размер окна по умолчанию огромен (занимает почти все мое экранное пространство 1440p). Приложение, которое я делаю, требует только около 600x600. Также было бы полезно иметь возможность зафиксировать размер окна, хотя я рад, что приложение просто отзывчиво.

9 ответов

.NET7 в Visual Studio 2022 17.4 представляет более элегантный способ сделать это, чем реализации .NET6. Для конкретного приложения Windows просто добавьте следующий код в App.xaml.cs.

      namespace sampleCode;

public partial class App : Application
{
    public App()
    {
        InitializeComponent();
        MainPage = new AppShell();
    }

    protected override Window CreateWindow(IActivationState activationState)
    {
        var window = base.CreateWindow(activationState);

        const int newWidth = 800;
        const int newHeight = 600;
        
        window.Width = newWidth;
        window.Height = newHeight;

        return window;
    }
}

Обновлено для Maui GA (я тоже добавлю к этому обсуждению):

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

namespace YourAppNameHere;

public partial class App : Application
{
    const int WindowWidth = 400;
    const int WindowHeight = 300;
    public App()
    {
        InitializeComponent();

        Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
        {
#if WINDOWS
            var mauiWindow = handler.VirtualView;
            var nativeWindow = handler.PlatformView;
            nativeWindow.Activate();
            IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
            WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
            AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
            appWindow.Resize(new SizeInt32(WindowWidth, WindowHeight));
#endif
        });

        MainPage = new MainPage();
    }
    ...

ИЛИ, если вы хотите основывать его на запрошенных размерах MainPage, прежде чем обработчик добавления может сделать:

              MainPage = new MainPage();
        var width = (int)MainPage.WidthRequest;
        var height = (int)MainPage.HeightRequest;

затем используйте эти размеры (возможно, добавьте некоторые отступы, чтобы получить размер всего окна, потому что MainPage - это клиентская область).


ПРИМЕЧАНИЕ. Я тестировал для Windows, поэтому в раскрывающемся списке в верхнем левом углу панели редактора исходного текста я выбрал ... (net6.0-windows10.0.19041.0). Вот почему я не заметил, что мне нужно #ifвокруг usings, чтобы избежать ошибок на Android и т. д.

С сентября 2022 года это можно сделать проще:

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

        MainPage = new AppShell();    
    }

    protected override Window CreateWindow(IActivationState activationState)
    {
        Window window = base.CreateWindow(activationState);
        window.Activated += Window_Activated;
        return window;
    }

    private async void Window_Activated(object sender, EventArgs e)
    {
    #if WINDOWS
        const int DefaultWidth = 1024;
        const int DefaultHeight = 800;

        var window = sender as Window;

        // change window size.
        window.Width = DefaultWidth;
        window.Height = DefaultHeight;

        // give it some time to complete window resizing task.
        await window.Dispatcher.DispatchAsync(() => { });

        var disp = DeviceDisplay.Current.MainDisplayInfo;

        // move to screen center
        window.X = (disp.Width / disp.Density - window.Width) / 2;
        window.Y = (disp.Height / disp.Density - window.Height) / 2;
    #endif    
    }
}

Связанный билет: https://github.com/dotnet/maui/pull/4942

Вот как мы это сделали:

https://github.com/BhangeeF16/MAUI-DOT-NET/blob/main/SampleApp/MauiProgram.cs

ВMauiProgram.cs>CreateMauiApp

      #if WINDOWS
        builder.ConfigureLifecycleEvents(events =>
        {
            events.AddWindows(wndLifeCycleBuilder =>
            {
                wndLifeCycleBuilder.OnWindowCreated(window =>
                {
                    IntPtr nativeWindowHandle = WinRT.Interop.WindowNative.GetWindowHandle(window);
                    WindowId win32WindowsId = Win32Interop.GetWindowIdFromWindow(nativeWindowHandle);
                    AppWindow winuiAppWindow = AppWindow.GetFromWindowId(win32WindowsId);    
                    if(winuiAppWindow.Presenter is OverlappedPresenter p)
                    { 
                       p.Maximize();
                       //p.IsAlwaysOnTop=true;
                       p.IsResizable=false;
                       p.IsMaximizable = false;
                       p.IsMinimizable=false;
                    }                     
                    else
                    {
                        const int width = 1920;
                        const int height = 1080;
                        winuiAppWindow.MoveAndResize(new RectInt32(1920 / 2 - width / 2, 1080 / 2 - height / 2, width, height));                      
                    }                        
                });
            });
        });
#endif     

Как установить начальный размер окна и отцентрировать его (maui 7.0.59):

      public partial class App : Application {

    public App() {
        InitializeComponent();
        MainPage = new AppShell();
    }

    protected override Window CreateWindow(IActivationState activationState) {
        var window = base.CreateWindow(activationState);
        window.Created += Window_Created;
        return window;
    }

    private async void Window_Created(object sender, EventArgs e) {
        const int defaultWidth = 1200;
        const int defaultHeight = 800;

        var window = (Window)sender;
        window.Width = defaultWidth;
        window.Height = defaultHeight;
        window.X = -defaultWidth;
        window.Y = -defaultHeight;

        await window.Dispatcher.DispatchAsync(() => {});

        var displayInfo = DeviceDisplay.Current.MainDisplayInfo;
        window.X = (displayInfo.Width / displayInfo.Density - window.Width) / 2;
        window.Y = (displayInfo.Height / displayInfo.Density - window.Height) / 2;
    }

}

Ненавижу, что не могу просто внести это незначительное изменение в комментарий вместо того, чтобы дать совершенно новый ответ, но это ТАК для вас.

Вы можете контролировать размер окна и включать максимизацию/минимизацию/изменение размера, изменив реализацию конкретной платформы Windows на следующую (в). Это позволяет избежать необходимости заключать код конкретной платформы в элементы функции #if.

          public partial class App : MauiWinUIApplication
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();

            Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
            {
                var mauiWindow = handler.VirtualView;
                var nativeWindow = handler.PlatformView;
                nativeWindow.Activate();

                // allow Windows to draw a native titlebar which respects IsMaximizable/IsMinimizable
                nativeWindow.ExtendsContentIntoTitleBar = false;

                IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
                WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
                AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);

                // set a specific window size
                appWindow.Resize(new SizeInt32(480, 720));

                if (appWindow.Presenter is OverlappedPresenter p)
                {
                    p.IsResizable = false;

                    // these only have effect if XAML isn't responsible for drawing the titlebar.
                    p.IsMaximizable = false;
                    p.IsMinimizable = false;
                }
            });
        }

        protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
    }

Если вы хотите сделать это только для настольных платформ, вы можете сделать что-то похожее на @ToolmakerSteve, но для каждой платформы, переопределив функцию OnLaunched внапример.

      using Microsoft.UI;
using Microsoft.UI.Windowing;
using Windows.Graphics;
using WinRT.Interop;
//...
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    base.OnLaunched(args);

    var currentWindow = Application.Windows[0].Handler.PlatformView;
    IntPtr _windowHandle = WindowNative.GetWindowHandle(currentWindow);
    var windowId = Win32Interop.GetWindowIdFromWindow(_windowHandle);

    AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
    appWindow.Resize(new SizeInt32(350, 600));
}

Эти методы изменения размера все еще не идеальны, так как они будут мерцать при изменении размера окна. Это просто из-за времени, которое проходит между запуском OnLaunch и изменением размера окна собственными вызовами API win32. Однако перенос его непосредственно в код, специфичный для платформы, немного более семантичен.

В отличие от другого ответа, мы не можем получить запрошенные размеры с клиентских страниц для использования в качестве размеров нашего окна.

Это сработало для меня:

          const int WindowWidth = 400;
    const int WindowHeight = 300;

    public App()
    {
        InitializeComponent();
        
        Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
        {
#if WINDOWS
            var mauiWindow = handler.VirtualView;
            var nativeWindow = handler.PlatformView;

            nativeWindow.Activate();
            IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);

            var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
            var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);

            appWindow.Resize(new Windows.Graphics.SizeInt32(WindowWidth, WindowHeight));
#endif
        });

        MainPage = new AppShell();
    }

[Согласитесь с предыдущим ответом относительно редактирования и комментариев (также требования к репутации для комментариев)]

Для тех, кто предпочитает использовать подход «Платформы/Windows/App.xaml.cs», вы можете легко получить размер экрана, добавив в код обработчик событий «Активированный» (просто расширить, если вам также нужен displayInfo.Density). :

      public partial class App : MauiWinUIApplication
{
    Microsoft.UI.Xaml.Window nativeWindow;
    int screenWidth, screenHeight;
    const int desiredWidth = 480;
    const int desiredHeight = 720;
    /// <summary>
    /// Initializes the singleton application object.  This is the first line of authored code
    /// executed, and as such is the logical equivalent of main() or WinMain().
    /// </summary>
    public App()
    {
        this.InitializeComponent();

        Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
        {
            IWindow mauiWindow = handler.VirtualView;
            nativeWindow = handler.PlatformView;
            nativeWindow.Activated += OnWindowActivated;
            nativeWindow.Activate();

            // allow Windows to draw a native titlebar which respects IsMaximizable/IsMinimizable
            nativeWindow.ExtendsContentIntoTitleBar = false;

            IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
            WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
            AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);

            // set a specific window size
            appWindow.MoveAndResize(new RectInt32((screenWidth - desiredWidth) / 2, (screenHeight - desiredHeight) / 2, desiredWidth, desiredHeight));

            if (appWindow.Presenter is OverlappedPresenter p)
            {
                p.IsResizable = false;
                // these only have effect if XAML isn't responsible for drawing the titlebar.
                p.IsMaximizable = false;
                p.IsMinimizable = false;
            }
        });
    }

    private void OnWindowActivated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args)
    {
        // Retrieve the screen resolution
        var displayInfo = DeviceDisplay.Current.MainDisplayInfo;
        screenWidth = (int)displayInfo.Width;
        screenHeight = (int)displayInfo.Height;
        // Remove this event handler since it is not needed anymore
        nativeWindow.Activated -= OnWindowActivated;
    }
Другие вопросы по тегам