如何强制WPF启动窗口到特定的屏幕?

我有一个WPF应用程序,它将通过专用窗口显示有关投影仪的信息。 我想配置用于投影仪显示的屏幕以及用于主应用程序窗口的内容。

此代码将在指定屏幕上生成投影仪输出:

var screen = GetProjectorScreen(); _projectorWindow = new ProjectorWindow(); _projectorWindow.Left = screen.WorkingArea.Left; _projectorWindow.Top = screen.WorkingArea.Top; _projectorWindow.Owner = _parentWindow; _projectorWindow.Show(); public static Screen GetProjectorScreen() { var screens = Screen.AllScreens; if (screens.Length > 1 && Settings.Default.DisplayScreen < screens.Length) { return screens[Settings.Default.DisplayScreen]; } return screens[0]; } 

我试图用启动forms做同样的技巧,但到目前为止还没有成功。 我试图在MainWindow构造函数中设置Top和Left属性,但这不起作用。

通过设置StartupUri从App.xaml.cs启动启动窗口:

 StartupUri = new Uri("Windows/MainWindow.xaml", UriKind.Relative); 

有没有其他方法来启动启动表单? 我试图只调用构造函数,但这会导致崩溃,因为某些资源不再被加载。

我搞定了。 在设置窗口位置之前,必须将WindowState设置为Normal。 并且在创建窗口之前,即在构造函数调用之后,该设置将根本不起作用。 因此,我在Windows_Loaded事件中调用显式设置。 如果需要移动窗口,这可能会导致闪烁,但这对我来说是可以接受的。

在用户手动更改屏幕设置后,也应调用SetScreen方法。

 private void SetScreen() { var mainScreen = ScreenHandler.GetMainScreen(); var currentScreen = ScreenHandler.GetCurrentScreen(this); if (mainScreen.DeviceName != currentScreen.DeviceName) { this.WindowState = WindowState.Normal; this.Left = mainScreen.WorkingArea.Left; this.Top = mainScreen.WorkingArea.Top; this.Width = mainScreen.WorkingArea.Width; this.Height = mainScreen.WorkingArea.Height; this.WindowState = WindowState.Maximized; } } 

备份ScreenHandler实用程序非常简单:

 public static class ScreenHandler { public static Screen GetMainScreen() { return GetScreen(Settings.Default.MainScreenId); } public static Screen GetProjectorScreen() { return GetScreen(Settings.Default.ProjectorScreenId); } public static Screen GetCurrentScreen(Window window) { var parentArea = new Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height); return Screen.FromRectangle(parentArea); } private static Screen GetScreen(int requestedScreen) { var screens = Screen.AllScreens; var mainScreen = 0; if (screens.Length > 1 && mainScreen < screens.Length) { return screens[requestedScreen]; } return screens[0]; } } 

已接受的答案在应用程序清单中的每台显示器DPI上不再适用于Windows 10。

这对我有用:

 public partial class MyWindow : Window { readonly Rectangle screenRectangle; public MyWindow( System.Windows.Forms.Screen screen ) { screenRectangle = screen.WorkingArea; InitializeComponent(); } [DllImport( "user32.dll", SetLastError = true )] static extern bool MoveWindow( IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint ); protected override void OnSourceInitialized( EventArgs e ) { base.OnSourceInitialized( e ); var wih = new WindowInteropHelper( this ); IntPtr hWnd = wih.Handle; MoveWindow( hWnd, screenRectangle.Left, screenRectangle.Top, screenRectangle.Width, screenRectangle.Height, false ); } void Window_Loaded( object sender, RoutedEventArgs e ) { WindowState = WindowState.Maximized; } } 

只设置Left / Top不起作用。 根据我的测试,每个监视器DPI感知仅在窗口已经创建并放置在某个监视器上之后启动。 在此之前,窗口的左/上属性显然与主监视器的DPI成比例。

对于每个监视器DPI和监视器布局的某些组合,这会导致将Left / Top属性设置为System.Windows.Forms.Screen矩形的像素值导致窗口位于其他位置的错误。

以上解决方法仅适用于最大化,并不总是设置窗口的正确大小。 但至少它设置了正确的左上角,这足以使最大化正常工作。