У меня есть приложение Winui 3. Мне нужно открыть новое окно на дополнительном мониторе, как только пользователь нажмет кнопку. Я нашел сообщение ниже, которое работает для UWP. Открыть новое окно на дополнительном мониторе в UWP Однако этот код не работает в Winui 3.
private async void NewWindow()
{
var myview = CoreApplication.CreateNewView();
int newid = 0;
await myview.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Frame newframe = new Frame();
newframe.Navigate(typeof(Newpage), null);
Window.Current.Content = newframe;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = "Z";
newid = ApplicationView.GetForCurrentView().Id;
});
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newid, ViewSizePreference.UseMinimum);
}
Я получаю сообщение об ошибке «System.InvalidOperationException: метод был вызван в неожиданное время». в var myview = CoreApplication.CreateNewView(); строке.
Я провел много исследований, но не смог найти ничего, связанного с отображением окна на дополнительном мониторе для Winui 3. Пожалуйста, помогите мне с отображением окна на другом мониторе с Winui 3.
@SimonMourier Спасибо за комментарий. На самом деле я изо всех сил пытаюсь выяснить положение вторичного монитора. Не могли бы вы помочь мне с этим?





Приложения UWP имеют только одно окно, а WinUI3 может создавать новые. Как открыть новое окно в WinUI3 с помощью WinRT/C++?.
Теперь, чтобы переместить окно на другой экран, теоретически вы должны иметь возможность использовать класс WinUI3 DisplayArea.
Но проблема в том, что его метод FindAll не работает (уже некоторое время...), как сообщается здесь; Итератор Microsoft.UI.Windowing.DisplayArea.FindAll выдает «Invalid Cast
Также есть DisplayManager, DisplayTarget и т. д. WinRT. но они не очень просты в использовании... И мы не можем использовать класс Winforms Screen...
Итак, еще одно решение — использовать «классическое» взаимодействие .NET, например:
var window = new Window();
window.Content = new TextBlock() { Text = "Hello" };
window.Activate();
var monitors = Monitor.All.ToArray();
if (monitors.Length > 1)
{
var thisMonitor = Monitor.FromWindow(WinRT.Interop.WindowNative.GetWindowHandle(this));
var otherMonitor = monitors.First(m => m.DeviceName != thisMonitor.DeviceName);
// move to second display's upper left corner
window.AppWindow.Move(new PointInt32(otherMonitor.WorkingArea.X, otherMonitor.WorkingArea.Y));
}
С этим Monitor классом:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Windows.Graphics;
public sealed class Monitor
{
private Monitor(IntPtr handle)
{
Handle = handle;
var mi = new MONITORINFOEX();
mi.cbSize = Marshal.SizeOf(mi);
if (!GetMonitorInfo(handle, ref mi))
throw new Win32Exception(Marshal.GetLastWin32Error());
DeviceName = mi.szDevice.ToString();
Bounds = new RectInt32(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top);
WorkingArea = new RectInt32(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top);
IsPrimary = mi.dwFlags.HasFlag(MONITORINFOF.MONITORINFOF_PRIMARY);
}
public IntPtr Handle { get; }
public bool IsPrimary { get; }
public RectInt32 WorkingArea { get; }
public RectInt32 Bounds { get; }
public string DeviceName { get; }
public static IEnumerable<Monitor> All
{
get
{
var all = new List<Monitor>();
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, (m, h, rc, p) =>
{
all.Add(new Monitor(m));
return true;
}, IntPtr.Zero);
return all;
}
}
public override string ToString() => DeviceName;
public static IntPtr GetNearestFromWindow(IntPtr hwnd) => MonitorFromWindow(hwnd, MFW.MONITOR_DEFAULTTONEAREST);
public static IntPtr GetDesktopMonitorHandle() => GetNearestFromWindow(GetDesktopWindow());
public static IntPtr GetShellMonitorHandle() => GetNearestFromWindow(GetShellWindow());
public static Monitor FromWindow(IntPtr hwnd, MFW flags = MFW.MONITOR_DEFAULTTONULL)
{
var h = MonitorFromWindow(hwnd, flags);
return h != IntPtr.Zero ? new Monitor(h) : null;
}
[Flags]
public enum MFW
{
MONITOR_DEFAULTTONULL = 0x00000000,
MONITOR_DEFAULTTOPRIMARY = 0x00000001,
MONITOR_DEFAULTTONEAREST = 0x00000002,
}
[Flags]
public enum MONITORINFOF
{
MONITORINFOF_NONE = 0x00000000,
MONITORINFOF_PRIMARY = 0x00000001,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct MONITORINFOEX
{
public int cbSize;
public RECT rcMonitor;
public RECT rcWork;
public MONITORINFOF dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szDevice;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
private delegate bool MonitorEnumProc(IntPtr monitor, IntPtr hdc, IntPtr lprcMonitor, IntPtr lParam);
[DllImport("user32")]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32")]
private static extern IntPtr GetShellWindow();
[DllImport("user32")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
[DllImport("user32")]
private static extern IntPtr MonitorFromWindow(IntPtr hwnd, MFW flags);
[DllImport("user32", CharSet = CharSet.Unicode)]
private static extern bool GetMonitorInfo(IntPtr hmonitor, ref MONITORINFOEX info);
}
Большое спасибо !!. Это решило мои проблемы. Однако мне пришлось сделать одну модификацию. AppWindow напрямую не доступен для окна (window.AppWindow не работает). Мне пришлось использовать Interop, чтобы получить окно приложения, как показано ниже. IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(окно); WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd); var appWindow = AppWindow.GetFromWindowId(windowId);
Свойство @Chamal AppWindow доступно в последних версиях WinAppSDK (learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/… ). Убедитесь, что вы обновили соответствующие пакеты nuget.
Создать новое окно очень просто: stackoverflow.com/a/69235394/403671 и вы можете переместить это окно с помощью window.AppWindow.Move, т.е.:
window.AppWindow.Move(new Windows.Graphics.PointInt32(3000, 3000));