microsoft-ui-xaml icon indicating copy to clipboard operation
microsoft-ui-xaml copied to clipboard

Proposal: Window Width/Height in Desktop

Open JVimes opened this issue 5 years ago โ€ข 38 comments

Proposal: Support Window Width/Height when in Desktop

Summary

For WinUI in Desktop apps:

  • Support setting Width and Height on Window in XAML.
  • Support setting d:DesignWidth and d:DesignHeight on Window in XAML.
<Window Width="1200" Height="600"
        d:DesignWidth="1000" d:DesignHeight="500">

Rationale

Many developers doing WinUI in Desktop will have a background in WPF and/or simply not be interested in doing a responsive design -- this is "in Desktop" after all. Without the ability to set Window size in a traditional way, I believe adoption will suffer due to too much forced change.

JVimes avatar Jun 23 '20 04:06 JVimes

@JVimes, thanks for opening this request. I believe there should be APIs that allow developers to do this. The APIs should work for both, UWP and Desktop.

marb2000 avatar Jun 24 '20 16:06 marb2000

@marb2000 It appears not: image

JVimes avatar Jun 25 '20 01:06 JVimes

@JVimes, thanks for opening this request. I believe there should be APIs that allow developers to do this. The APIs should work for both, UWP and Desktop.

I'm wondering if there is any API to manage window size/position at all?

alexandrevk avatar Sep 27 '20 21:09 alexandrevk

While these APIs doesn't exist in Desktop WinUI 3 apps, I published a sample to workaround it using the Win32 APIs.

Using the SetWindowPos API you can set the size and/or the position of a Window object.

marb2000 avatar Nov 23 '20 21:11 marb2000

Thanks for the workaround, @marb2000. The code also looks like a starting point to address the problem.

JVimes avatar Nov 25 '20 17:11 JVimes

I assume there's no progress to report on setting size for a UWP/Desktop window? Couldn't get that SetWindowPos example to work in my basic app unfortunately.

PylotLight avatar Feb 27 '21 12:02 PylotLight

Is there a workaround for getting the current size? I am working on an app whose layout is dependent on physical window size and just want to read the width of the window and am struggling to do so.

adderthorn avatar Apr 13 '21 00:04 adderthorn

Is there a workaround for getting the current size? I am working on an app whose layout is dependent on physical window size and just want to read the width of the window and am struggling to do so.

Would that size include any window borders, and titlebar height, or just the client drawing area?

mdtauk avatar Apr 13 '21 01:04 mdtauk

Ideally, just the client size.

On Mon, Apr 12, 2021, 21:24 Martin Anderson @.***> wrote:

Is there a workaround for getting the current size? I am working on an app whose layout is dependent on physical window size and just want to read the width of the window and am struggling to do so.

Would that size include any window borders, and titlebar height, or just the client drawing area?

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/microsoft/microsoft-ui-xaml/issues/2731#issuecomment-818362600, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA5H6G26Q5AANEXOWVVXYP3TIOMNHANCNFSM4OFIVB3Q .

adderthorn avatar Apr 13 '21 01:04 adderthorn

You can find a couple of helpers in GitHub that tell you the width and height of the Window. using Win32 APIs, WinUIEx from @dotMorten and DeskopWindow.

To get the size of the client area you should ask for the size of the XamlRoot. You can get the XamlRoot property from any UIElement in the layout. It could be than the XamlRoot is still null in the constructor, so I recommend use Loaded for instance.

marb2000 avatar Apr 13 '21 03:04 marb2000

The AppWindow class has methods Move, Resize and MoveAndResize. These can be used to set the size and location for windows. They cannot be used to prevent the user from resizing windows, though.

You can get an AppWindow instance from a Window instance via:

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

chausner avatar Jan 17 '22 18:01 chausner

The AppWindow class has methods Move, Resize and MoveAndResize. These can be used to set the size and location for windows. They cannot be used to prevent the user from resizing windows, though.

You can get an AppWindow instance from a Window instance via:

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

I confirm it works. Thanks! But what exactly are this methods? why it's so difficult to obtain such a simple feature?

bogdan-patraucean avatar Jan 17 '22 22:01 bogdan-patraucean

๐Ÿ˜‚ ๐Ÿ˜‚ ๐Ÿ˜‚ UI library without ability to change window size.

bugproof avatar Mar 28 '22 12:03 bugproof

this is painful, and as a person trying to write in C++ i have no clue as to what i can possibly use/do to set window size

05-1 avatar Jun 21 '22 22:06 05-1

this is painful, and as a person trying to write in C++ i have no clue as to what i can possibly use/do to set window size

As it has been said AppWindow.Resize works correctly. And if you use C++, you have access without P/Invoke to all the Win32 APIs (SetWindowPos, MoveWindow, SetWindowPlacement, etc...)

castorix avatar Jun 22 '22 07:06 castorix

The AppWindow class has methods Move, Resize and MoveAndResize. These can be used to set the size and location for windows. They cannot be used to prevent the user from resizing windows, though.

You can get an AppWindow instance from a Window instance via:

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

You can use a Presenter for that

OverlappedPresenter overlappedPresenter = appWindow.Presenter as OverlappedPresenter;
overlappedPresenter.IsResizable = false;

eduardobragaxz avatar Jul 17 '22 00:07 eduardobragaxz

Note The AppWindow.Resize() requires the size to be already scaled using DPI of the monitor. It does not used the device independent values as WPF does.

jozefizso avatar Jun 09 '23 15:06 jozefizso

@jozefizso Correct. The AppWindow API is not really a WinUI3 API - It's a generic Windows API (which is why I was rather disappointed seeing a recent release exposing AppWindow as a property directly on Window to avoid the code @eduardobragaxz has above), instead of just providing a first-class set of properties and methods directly on the WinUI Window class that is fully DPI aware.

This is one of the reasons I created the WinUIEx extension to help with this stuff, as it's rather complicated to having to deal with.

dotMorten avatar Jun 09 '23 16:06 dotMorten

Aren't they working on converging Window and AppWindow?

eduardobragaxz avatar Jun 09 '23 23:06 eduardobragaxz

DesignHeight and DesignWidth would make sense if Microsoft actually bothered to add a designer for WinUI 3

mdtauk avatar Jun 10 '23 01:06 mdtauk

@eduardobragaxz From what I gather, they are converging behaviour on functionality exposed through both. This should essentially mean that Window.ExtendsContentIntoTitleBar will do the same thing as AppWindowTitleBar.ExtendsContentIntoTitleBar and Window.Title will do the same thing as AppWindow.Title. Maybe they will implement it in terms of Window calling through to AppWindow. For converging Window and AppWindow, that would be impossible if they want to keep to the currently documented fact that AppWindow is intended to be framework agnostic. Adding the Xaml functionality would go against this. We'll see how things go, but considering UWP WinUI, I wouldn't be surprised if Window never picks up anything else to control the underlying window and I would also not be surprised if eventually Window.Title and Window.ExtendsContentIntoTitleBar will end up marked as deprecated with the recommendation to use AppWindow.

DarranRowe avatar Jun 11 '23 18:06 DarranRowe

@DarranRowe ohhh that makes a lot more sense ๐Ÿ˜„ It feels like a good thing.

I know it isn't, but using AppWindow feels weirdly hacky

eduardobragaxz avatar Jun 13 '23 02:06 eduardobragaxz

Am I actually reading that there is no sane way to set the window size of a WinUI app? that seems... crazy. Am I crazy for thinking it's crazy? Or maybe I just can't read because I've been coding all day.

ELI7VH avatar Jul 22 '23 04:07 ELI7VH

Am I actually reading that there is no sane way to set the window size of a WinUI app? that seems... crazy. Am I crazy for thinking it's crazy? Or maybe I just can't read because I've been coding all day.

For now you can only do it in code. On the Window code behind you can do

this.AppWindow.Resize(new(width, height))

eduardobragaxz avatar Jul 22 '23 11:07 eduardobragaxz

Make sure you account for dpi

var scale = (this.Content as FrameworkElement).XamlRoot.RasterizationScale;
this.AppWindow.Resize(new((int)width*scale, (int)height*scale))

This is one reason that IMHO the AppWindow APIs really shouldnโ€™t have been a property directly on Window since it doesnโ€™t really understand WinUI and should have been reserved for non-WinUI scenarios.

dotMorten avatar Jul 22 '23 14:07 dotMorten

Hey thank you for the information, for some reason (after trying to code for 10 hours straight), I wasn't putting together that I needed to sue this new (w, h) data structure in the Resize.

Sorry my message was a bit salty, I am a web developer trying to do Windows UI layout and I am finding it a bit tedious to say the least ๐Ÿ˜…

In my main app, I will be using a web UI and just using sockets, etc to do most of the work, but even though my layout is minimal, it's still frustrating when I can't make it look nice hehe.

ELI7VH avatar Jul 22 '23 14:07 ELI7VH

I've just been bit by this as well while trying to render a splash screen with fixed dimensions. While trying to fix it by resizing the window using window.AppWindow().ResizeClient(), I hit another issue as window.Content().RasterizationScale() was being reported as 1.0 on a high-DPI display.

Having a Window API to accomplish this using logical pixels would be fantastic!

kasperisager avatar Jan 18 '24 16:01 kasperisager

To account for the seemingly incorrect scale reported by UIElement.RasterizationScale(), I'm instead using GetDpiForMonitor() to compute the correct scaling factor for the monitor, scale = float(dpi) / 96.

To get the monitor associated with a window before and/or after activation, I'm using the following methods:

  1. Primary monitor:

    MonitorFromPoint({0, 0}, MONITOR_DEFAULTTOPRIMARY);
    
  2. Monitor at (x, y) before activation:

    MonitorFromPoint({x, y}, MONITOR_DEFAULTTONEAREST);
    
  3. Monitor associated with window after activation:

    MonitorFromWindow(GetWindowFromWindowId(window.AppWindow().Id()), MONITOR_DEFAULTTONEAREST);
    

With that, and as others have pointed out, positioning and resizing the window can be done like this, making sure to premultiply the coordinates and dimensions by scale:

window.AppWindow().Move({int(x), int(y)});
window.AppWindow().ResizeClient({int(width), int(height)});

Keep in mind that this is all C++/WinRT. I'd be so happy with a direct Window API that would hide all of the above complexity ๐Ÿ™

kasperisager avatar Jan 19 '24 11:01 kasperisager

@kasperisage you should use the scale off XamlRoot

dotMorten avatar Jan 19 '24 14:01 dotMorten

@dotMorten How does that work with multi-monitor setups where the monitors have different DPIs? To be clear, I have to both move and resize the window, taking into account the DPI of the monitor that corresponds to the final position of the window. Both the position and dimension are provided in logical pixels.

kasperisager avatar Jan 19 '24 16:01 kasperisager