2

Idea is very simple open one or more windows in the app, save their size, position and monitor placement when closing the app, and then when they are opened again, every window should open on the same position, size and monitor they were closed on, I was able to do the size and position succesfully but monitor/DisplayRegion is giving me incorrect monitor, even when my secondary window is on 2nd monitor, It returns the first monitor (display region), I just need to figure out at the time of saving the placement data, how can I figure out that my specific secondary AppWindow is on which monitor/DisplayRegion?

Following code runs when app is closing

internal static void UpdateAppWindowsPlacements()
    {
        foreach (var item in AppWindowViewModels)
        {
            ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Show_{item.Key}"] = item.AppWindow != null;
            if (item.AppWindow != null)
            {
                var placement = item.AppWindow.GetPlacement();
                var regions = new List<DisplayRegion>(); 
                foreach (var dr in item.AppWindow.WindowingEnvironment.GetDisplayRegions())
                {
                    regions.Add(dr);// this list is just for testing, it gives me boh monitors/DisplayRegions, but no way to find out where this window resides.
                }
                //Size is full screen size and can be bigger bcz it also includes taskbar etc.
                //Display region excludes taskbar etc
                var displayRegion = placement.DisplayRegion;
                var displayRegionWidth = displayRegion.WorkAreaSize.Width;
                var displayRegionHeight = displayRegion.WorkAreaSize.Height;

                var sizeWidth = placement.Size.Width;
                var sizeHeight = placement.Size.Height;

                ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Width_{item.Key}"] = sizeWidth > displayRegionWidth ? displayRegionWidth : sizeWidth;
                ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Height_{item.Key}"] = sizeHeight > displayRegionHeight ? displayRegionHeight : sizeHeight;

                ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_X_{item.Key}"] = placement.Offset.X;
                ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Y_{item.Key}"] = placement.Offset.Y;
            }
        }
    }

Opening secondary windows and positioning them as per saved position

internal static async Task OpenSecondaryWindows(int total)
    {
        for (int i = 0; i < total; i++)
        {
            var appWindowViewModel = new AppWindowViewModel(i.ToString());
            AppWindowViewModels.Add(appWindowViewModel);
            var open = ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Show_{i}"];
            if (open == null)
            {
                ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Show_{i}"] = true;
                open = true;
            }
            if ((bool)open)
            {
                await View(appWindowViewModel);
            }
        }
    }
    private static async Task View(AppWindowViewModel appWindowViewModel)
    {
        if (appWindowViewModel.AppWindow is null)
        {
            appWindowViewModel.AppWindow = await AppWindow.TryCreateAsync();
            var frame = new Frame();
            frame.Navigate(typeof(SecondaryPage), appWindowViewModel.Key);
            ElementCompositionPreview.SetAppWindowContent(appWindowViewModel.AppWindow, frame);

            appWindowViewModel.AppWindow.Closed += delegate
            {
                frame.Content = null;
                appWindowViewModel.AppWindow = null;
            };
        }

        var shown = await appWindowViewModel.AppWindow.TryShowAsync();

        var windowWidth = ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Width_{appWindowViewModel.Key}"];
        var windowHeight = ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Height_{appWindowViewModel.Key}"];
        if (windowWidth is double wWidth && windowHeight is double wHeight)
        {
            appWindowViewModel.AppWindow.RequestSize(new Size(wWidth, wHeight));
        }

        var xposition = ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_X_{appWindowViewModel.Key}"];
        var yposition = ApplicationData.Current.LocalSettings.Values[$"AppWindow_SecondaryView_Y_{appWindowViewModel.Key}"];
        if (xposition is double xpos && yposition is double ypos)
        {
            var placement = appWindowViewModel.AppWindow.GetPlacement();
            appWindowViewModel.AppWindow.RequestMoveRelativeToDisplayRegion(placement.DisplayRegion, new Point(xpos, ypos));
        }
        else
        {
            appWindowViewModel.AppWindow.RequestMoveAdjacentToCurrentView();
        }
    }

I have a sample uwp app : https://github.com/touseefbsb/AppWindowRemember

you can clone it and run the MultiAppWindowSample2 project, enter "1" in the text box and press the button Open Secondary Windows. it will open 1 secondary window alongside the main window as expected, now move the 2nd window to your 2nd monitor and then close your main window it will ask whether you want to save the placement, press Yes.

Now run the app again, and enter "1" in textbox and press button again, notice the secondary window opens on your first monitor/display. While the aim is to open it on the 2nd monitor as it was closed the last time.

Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75

3 Answers3

1

UWP AppWindow Get correct monitor/Display region

The problem is the DisplayRegion of current AppWindow is always the first monitor even if you have moved the AppWindow into the second monitor. I will report this problem. and currently there is work around is show AppWindow in the second monitor at first and record the second monitor's id into local setting.

During the testing ApplicationView.GetForCurrentView().GetDisplayRegions()[0] could return correct DisplayRegion for current main app window (does not return correct value when move current into other monitor). you can use it to direct which is second monitor.

private DisplayRegion GetOtherDisplayRegion(DisplayRegion currentAppDisplayRegion)
{
    // Get the list of all DisplayRegions defined for the WindowingEnvironment that our application is currently in
    IReadOnlyList<DisplayRegion> displayRegions = ApplicationView.GetForCurrentView().WindowingEnvironment.GetDisplayRegions();
    foreach (DisplayRegion displayRegion in displayRegions)
    {
        if (displayRegion != currentAppDisplayRegion && displayRegion.IsVisible)
        {
            return displayRegion;
        }
    }

    return null;
}

For more please refer to official code sample .

Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • 1
    but this cant make it dynamic i.e : when I close the app there is no way to find out where exactly all my secondary windows are, (some can be on first monitor some on 2nd and maybe even 3rd) we wanted to make it dynamic so we can reopen all windows where they existed in last session. – Muhammad Touseef Apr 27 '22 at 01:47
  • Yep, this workaround is very limit, I have reported this problem and wish it could be fixed in the feature . – Nico Zhu Apr 27 '22 at 06:58
  • hi@MuhammadTouseef In that case it was determined that this was a bug, and the better way is report this bug in winui github. if you have report it please share the link below, I will help to vote it up. – Nico Zhu May 05 '22 at 04:19
  • but its part of sdk and not winui i think ? – Muhammad Touseef May 06 '22 at 12:05
  • `AppWindow ` could be reported in winui github, and it is better for tracking the outcome . – Nico Zhu May 09 '22 at 01:17
0

The bug only appeared on Windows 11. The device id is wrong but the offset is right, so we can use the right window offset and device offset to calculate the right device.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 14 '22 at 16:05
0

First, you must save the DisplayRegion.DisplayMonitorDeviceId (or something to recover on reload). I successfully used the ID.

Then you can get a list of DisplayRegions availible through either the AppWindow.WindowingEnvironment.GetDisplayRegions() or Windows.UI.WindowManagement.WindowingEnvironment.GetDisplayRegions(). This list is not debug viewable, but does work with foreach.

Walk the list and find the matching device, then RequestMoveRelativeToDisplayRegion. The ids in the struct require recasting to "string" to compare correctly.

The coordinates passed are relative to the DisplayRegion [monitor] and will be offset from 0,0 even if the monitor is positioned in negative space from the main monitor.

I just found this sample yesterday and figured out the solution. I need to offer an update to the original article and github sample, but I didn't bring the link home.