Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Window Width/Height in Desktop #2731

Open
JVimes opened this issue Jun 23, 2020 · 38 comments
Open

Proposal: Window Width/Height in Desktop #2731

JVimes opened this issue Jun 23, 2020 · 38 comments
Labels
area-AppWindow feature proposal New feature proposal needs-winui-3 Indicates that feature can only be done in WinUI 3.0 or beyond. (needs winui 3) product-winui3 WinUI 3 issues team-CompInput Issue for IXP (Composition, Input) team

Comments

@JVimes
Copy link

JVimes commented Jun 23, 2020

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 JVimes added the feature proposal New feature proposal label Jun 23, 2020
@msft-github-bot msft-github-bot added the needs-triage Issue needs to be triaged by the area owners label Jun 23, 2020
@marb2000 marb2000 added area-AppWindow needs-winui-3 Indicates that feature can only be done in WinUI 3.0 or beyond. (needs winui 3) team-Reach Issue for the Reach team product-winui3 WinUI 3 issues and removed needs-triage Issue needs to be triaged by the area owners labels Jun 24, 2020
@marb2000 marb2000 self-assigned this Jun 24, 2020
@marb2000
Copy link
Contributor

@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.

@JVimes
Copy link
Author

JVimes commented Jun 25, 2020

@marb2000 It appears not:
image

@alexandrevk
Copy link

@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?

@marb2000
Copy link
Contributor

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.

@JVimes
Copy link
Author

JVimes commented Nov 25, 2020

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

@PylotLight
Copy link

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.

@adderthorn
Copy link

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.

@mdtauk
Copy link
Contributor

mdtauk commented Apr 13, 2021

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?

@adderthorn
Copy link

adderthorn commented Apr 13, 2021 via email

@marb2000
Copy link
Contributor

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.

@chausner
Copy link

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);

@bogdan-patraucean
Copy link

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?

@bugproof
Copy link

bugproof commented Mar 28, 2022

😂 😂 😂
UI library without ability to change window size.

@05-1
Copy link

05-1 commented Jun 21, 2022

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

@castorix
Copy link

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...)

@eduardobragaxz
Copy link

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;

@jozefizso
Copy link

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.

@dotMorten
Copy link
Contributor

dotMorten commented Jun 9, 2023

@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.

@eduardobragaxz
Copy link

Aren't they working on converging Window and AppWindow?

@mdtauk
Copy link
Contributor

mdtauk commented Jun 10, 2023

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

@DarranRowe
Copy link

@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.

@eduardobragaxz
Copy link

@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

@ELI7VH
Copy link

ELI7VH commented Jul 22, 2023

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.

@eduardobragaxz
Copy link

eduardobragaxz commented Jul 22, 2023

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))

@dotMorten
Copy link
Contributor

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.

@ELI7VH
Copy link

ELI7VH commented Jul 22, 2023

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.

@bpulliam bpulliam added team-CompInput Issue for IXP (Composition, Input) team and removed team-Reach Issue for the Reach team labels Aug 23, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot added the needs-triage Issue needs to be triaged by the area owners label Aug 23, 2023
@bpulliam bpulliam removed the needs-triage Issue needs to be triaged by the area owners label Oct 18, 2023
@kasperisager
Copy link

kasperisager commented Jan 18, 2024

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
Copy link

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 🙏

@dotMorten
Copy link
Contributor

@kasperisage you should use the scale off XamlRoot

@kasperisager
Copy link

@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.

@dotMorten
Copy link
Contributor

dotMorten commented Jan 19, 2024

those APIs work in physical, not logical pixels (you can tell by the fact that they take integers and not doubles). You take the DPI into account, by multiplying the size you want in logical pixels, and multiply by the xamlroot resolutionscale. That's the size you pass to ResizeClient. Moving windows in logical pixels doesn't quite make sense, because as you say it could change across monitors, and Windows as a whole manages window locations in physical pixels. XamlRoot.ResolutionScale will change if you move to a monitor with a different scale set.

@kasperisager
Copy link

@dotMorten Apologies, I should have been more clear: The APIs I'm writing operate in logical pixels, hence this whole exercise to translate to the AppWindow() APIs which, as you mention, operate in physical pixels. Callers of the APIs I'm writing initialise windows by giving an (x, y) position and a width x height size, all in logical pixels. That's a pretty hard requirement as WinUI is just one of the supported backends.

It'd be fantastic with a window.Move() API that operates in logical pixels to hide all the DPI gymnastics. This issue was really only about sizing, however, so I'll stick to that.

@jozefizso
Copy link

Is it really impossible to have a simple API to set the application window sizes?

@RobertCXC
Copy link

Is Microsoft serious about this?

@Bart76
Copy link

Bart76 commented Jul 29, 2024

For my newest desktop application in C#, I am looking for a nice modern approach. So I am currently looking into WinUI 3. My first attempt in a simple demo project is setting an explicit initial size/dimension for the resizable main window. And I am shocked reading this issue thread and learning that that's not possible. (I do not consider any of the proposed obscure workarounds a serious solutions to this no-brainer.)

As I see it, I consider the ability to provide an initial size for windows/forms in a desktop application to be quite important. I am wondering what product vision has led to the omission of such basic functionality. (Perhaps it is mainly focused on mobile app/UI development?)

So after just 5 minutes of playing around, I am already convinced that WinUI will not the way to go for my future desktop application development projects. Since my current project will be a pure Windows application, I will turn to WPF. And if WPF turns out to be not very interesting as well, I will probably stay with WinForms while I consider a non-.NET development strategy for the future. :/

@castorix
Copy link

castorix commented Jul 29, 2024

For my newest desktop application in C#, I am looking for a nice modern approach. So I am currently looking into WinUI 3. My first attempt in a simple demo project is setting an explicit initial size/dimension for the resizable main window. And I am shocked reading this issue thread and learning that that's not possible. (I do not consider any of the proposed obscure workarounds a serious solutions to this no-brainer.)

The answer from chausner is usually sufficient
or for example :

this.AppWindow.MoveAndResize(new Windows.Graphics.RectInt32(100, 100, 500, 500));

@dotMorten
Copy link
Contributor

It’s not though. The window will be way too small on a high-res monitor. The size needs to be multiplied but the scaling factor of the monitor the window is opening on.

@ctmatt
Copy link

ctmatt commented Aug 19, 2024

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);

This seems to work even with 300% UI scaling. note ResizeCLIENT

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            shell = new Shell();
            shell.Activate();

            IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(shell);
            WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
            AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
            appWindow.ResizeClient(new Windows.Graphics.SizeInt32() { Width = 1800, Height = 1000 });
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-AppWindow feature proposal New feature proposal needs-winui-3 Indicates that feature can only be done in WinUI 3.0 or beyond. (needs winui 3) product-winui3 WinUI 3 issues team-CompInput Issue for IXP (Composition, Input) team
Projects
None yet
Development

No branches or pull requests