如何强制WPF启动窗口到特定的屏幕?(How to force WPF startup window

2019-07-03 14:20发布

我有一个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];
}

我曾尝试做启动窗体同样的伎俩,但至今没有成功。 我试图在主窗口的构造函数来设置上和左属性,但没有奏效。

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

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

是否有任何其他的方法来启动启动窗体? 我想只要调用构造函数,但导致崩溃,因为一些资源不再加载。

Answer 1:

我得到它的工作。 这是必要的设置窗口位置之前的WindowState设置为正常。 而直到创建该窗口的设置将不会在所有的工作,构造函数调用之后即。 因此,我呼吁在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];
    }
}


Answer 2:

接受的答案不再是应用的清单适用于Windows 10,每个显示器DPI。

下面是我工作:

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

只设置左/前不起作用。 根据我的测试,已经创建并放置一些显示器上后窗口每个显示器DPI意识只踢英寸 在此之前,显然是左/与主显示器的DPI窗口规模的Top属性。

对于每监视器DPI和显示器布局的一些组合,这造成在那里设置左/ Top属性到System.Windows.Forms.Screen矩形的像素值中的错误引起待别处定位该窗口。

上述解决办法是只适合最大化,它并不总是设置窗口的正确尺寸。 但至少它设置正确的左上角是不够的最大化才能正常工作。



文章来源: How to force WPF startup window to specific screen?