英文:
Winui 3 open a new window in secondary monitor
问题
I have a WinUI 3 application. I need to open a new window in a secondary monitor once the user clicks on a button. I found the following post, which works for UWP.
https://stackoverflow.com/questions/53923498/open-new-window-on-secondary-monitor-in-uwp
However, this code is not working in 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);
}
I am getting an error "System.InvalidOperationException: 'A method was called at an unexpected time.'" at the var myview = CoreApplication.CreateNewView();
line.
I did a lot of research but couldn't find anything related to displaying a window on a secondary monitor for WinUI 3. Please help me with displaying a window on another monitor with WinUI 3.
英文:
I have a Winui 3 application. I need to open a new window in secondary monitor once user clicked on a button. I found below post which works for UWP.
https://stackoverflow.com/questions/53923498/open-new-window-on-secondary-monitor-in-uwp
However this code is not working in 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);
}
I am getting an error "System.InvalidOperationException: 'A method was called at an unexpected time." at var myview = CoreApplication.CreateNewView();
line.
I did a lot of research but couldn't find anything related to display window in secondary monitor for winui 3. Please help me with displaying a window in another monitor with Winui 3.
答案1
得分: 3
UWP应用程序只有一个窗口,而WinUI3可以创建新的窗口。如何在WinUI3中使用WinRT/C++打开新窗口?。
现在,理论上,要将窗口移动到另一个屏幕,您应该能够使用WinUI3的DisplayArea类。
但问题是它的FindAll
方法有问题(一段时间了...),如此报道; Microsoft.UI.Windowing.DisplayArea.FindAll迭代器引发“Invalid Cast”错误。
还有WinRT的DisplayManager、DisplayTarget等,但它们不太容易使用... 而且我们不能使用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);
// 移动到第二个显示器的左上角
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
{
// ...
}
英文:
UWP apps have only one windows while WinUI3 can create new ones. How do I open a new Window in WinUI3 with WinRT/C++?.
Now, to move the window to another screen, in theory, you should be able to use WinUI3's DisplayArea class.
But the problem is its FindAll
method is broken (for some time now...) as reported here; Microsoft.UI.Windowing.DisplayArea.FindAll iterator throws "Invalid Cast
There's also WinRT's DisplayManager, DisplayTarget, etc. but they're not super easy to use... And we can't use Winforms' Screen
class...
So, one other solution is to use "classic" .NET interop, like this:
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));
}
With this Monitor
class:
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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论