WPF 中关于 Screen 的问题(主副屏)

Posted xiefang2008

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF 中关于 Screen 的问题(主副屏)相关的知识,希望对你有一定的参考价值。

WPF 及 Winform 的 PrimaryScreen 不同用法

https://blog.csdn.net/wzhiu/article/details/7187291

WPF:

this.Top = System.Windows.SystemParameters.WorkArea.Height - this.Height;
this.Left = System.Windows.SystemParameters.WorkArea.Width - this.Width;

Winform:

this.Top = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - this.Height;
this.Left = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - this.Width;

 

Show and Maximize WPF window on a specific screen

Question:

I‘m using the following method to display a WPF Window on a specific screen:

private void ShowOnMonitor(int monitor,Window window)
{
    Screen[] screens = Screen.AllScreens;

    window.WindowStyle = WindowStyle.None;
    window.WindowStartupLocation = WindowStartupLocation.Manual;

    window.Left = screens[monitor].Bounds.Left;
    window.Top = screens[monitor].Bounds.Top;
    //window.WindowState = WindowState.Maximized;
    window.Show();
}

The problem is I need the Window to be Maximized to fill the whole screen but as soon as I set:

window.WindowState = WindowState.Maximized;

It keeps showing the Window Maximized but only on the first screen no matter what number I pass through to the ShowOnMonitor() method.

Replies

1. Found the answer for this problem from the below link

http://mostlytech.blogspot.in/2008/01/maximizing-wpf-window-to-second-monitor.html

We cannot maximize the window until the window is loaded when using multiple screens. so hook up a window loaded event and set the window state to Maximized.

private void ShowOnMonitor(int monitor, Window window)
{
    var screen = ScreenHandler.GetScreen(monitor);
    var currentScreen = ScreenHandler.GetCurrentScreen(this);
    window.WindowState = WindowState.Normal;
    window.Left = screen.WorkingArea.Left;
    window.Top = screen.WorkingArea.Top;
    window.Width = screen.WorkingArea.Width;
    window.Height = screen.WorkingArea.Height;
    window.Loaded += Window_Loaded;          
}

/*You can use this event for all the Windows*/
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    var senderWindow = sender as Window;
    senderWindow.WindowState = WindowState.Maximized;
}

ScreenHandler.cs

public static class ScreenHandler
{
    public static Screen GetCurrentScreen(Window window)
    {
        var parentArea = new System.Drawing.Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height);
        return Screen.FromRectangle(parentArea);
    }

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

 

2. I found another post on MSDN which also works:

private void ShowOnMonitor(int monitor,Window window)
{
    Screen[] screens = Screen.AllScreens;

    window.WindowStyle = WindowStyle.None;
    window.WindowStartupLocation = WindowStartupLocation.Manual;

    window.Left = screens[monitor].Bounds.Left;
    window.Top = screens[monitor].Bounds.Top;

    window.SourceInitialized += (snd, arg) => 
        window.WindowState = WindowState.Maximized;

    window.Show();
}

 

3. I am running into what I‘m sure is a problem with an obvious solution but where do I run ShowOnMonitor(monitor,window)? after InitializeComponent() in the MainWindow() class function but that doesn‘t seem to be the case.     I thought I would just need to run ShowOnMonitor(0,MainWindow); but it‘s saying ‘MainWindow is a type not a variable‘ which is true, so I‘m not sure how to access to the current MainWindow. 

EDIT:
Found the solution.  ‘this‘ is the window to pass.   ShowOnMonitor(0,this);
Also I tweaked ScreenHandler.cs:

if (screens.Length > 1 && mainScreen < screens.Length)
{
    if (screens.Length > requestedScreen)
    {
        return screens[requestedScreen];
    }
    else
    {
        return screens[screens.Length - 1];
    }
}

This conditional ensures that the requested monitor is within bounds and avoids a ‘dumb‘ crash in case a config xml or startup flag is malformed. 

 

How to get the size of the current screen in WPF?

https://stackoverflow.com/questions/1927540/how-to-get-the-size-of-the-current-screen-in-wpf

Question:

I know I can get the size of the primary screen by using

System.Windows.SystemParameters.PrimaryScreenWidth;
System.Windows.SystemParameters.PrimaryScreenHeight;

But how do I get the size of the current screen? (Multi-Screen users do not always use the primary screen and not all screens are using the same resolution, right?)

It would be nice to be able to acces the size from XAML, but doing so from code (C#) would suffice.

Answer:

1. I created a little wrapper around the Screen from System.Windows.Forms, currently everything works... Not sure about the "device independent pixels", though.

public class WpfScreen
{
    public static IEnumerable<WpfScreen> AllScreens()
    {
        foreach (Screen screen in System.Windows.Forms.Screen.AllScreens)
        {
            yield return new WpfScreen(screen);
        }
    }

    public static WpfScreen GetScreenFrom(Window window)
    {
        WindowInteropHelper windowInteropHelper = new WindowInteropHelper(window);
        Screen screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
        WpfScreen wpfScreen = new WpfScreen(screen);
        return wpfScreen;
    }

    public static WpfScreen GetScreenFrom(Point point)
    {
        int x = (int) Math.Round(point.X);
        int y = (int) Math.Round(point.Y);

        // are x,y device-independent-pixels ??
        System.Drawing.Point drawingPoint = new System.Drawing.Point(x, y);
        Screen screen = System.Windows.Forms.Screen.FromPoint(drawingPoint);
        WpfScreen wpfScreen = new WpfScreen(screen);

        return wpfScreen;
    }

    public static WpfScreen Primary
    {
        get { return new WpfScreen(System.Windows.Forms.Screen.PrimaryScreen); }
    }

    private readonly Screen screen;

    internal WpfScreen(System.Windows.Forms.Screen screen)
    {
        this.screen = screen;
    }

    public Rect DeviceBounds
    {
        get { return this.GetRect(this.screen.Bounds); }
    }

    public Rect WorkingArea
    {
        get { return this.GetRect(this.screen.WorkingArea); }
    }

    private Rect GetRect(Rectangle value)
    {
        // should x, y, width, height be device-independent-pixels ??
        return new Rect
                   {
                       X = value.X,
                       Y = value.Y,
                       Width = value.Width,
                       Height = value.Height
                   };
    }

    public bool IsPrimary
    {
        get { return this.screen.Primary; }
    }

    public string DeviceName
    {
        get { return this.screen.DeviceName; }
    }
}

2. As far as I know there is no native WPF function to get dimensions of the current monitor. Instead you could PInvoke native multiple display monitors functions, wrap them in managed class and expose all properties you need to consume them from XAML.

 

WPF: Multiple screens

https://stackoverflow.com/questions/17859414/wpf-multiple-screens

Question:

I‘m writing a screensaver in WPF. I have the screensaver working, however, it only displays on my main monitor. Is there a way to "black out" or draw graphics to additional monitors when the user has multiple displays? I‘ve done some searching around, but haven‘t found anything relevant.

UPDATE:

From ananthonline‘s answer below, I was able to accomplish the "black out" effect on non-primary displays using the following window:

<Window x:Class="ScreenSaver.BlackOut"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Cursor="None" WindowStyle="None" ResizeMode="NoResize" Background="Black">
</Window>

and initializing one for each screen in App.xaml.cs using the following process:

foreach (Screen s in Screen.AllScreens)
{
    if (s != Screen.PrimaryScreen)
    {
        BlackOut blackOut = new BlackOut();
        blackOut.Top = s.WorkingArea.Top;
        blackOut.Left = s.WorkingArea.Left;
        blackOut.Width = s.WorkingArea.Width;
        blackOut.Height = s.WorkingArea.Height;
        blackOut.Show();
    }
}

Note an import to System.Windows.Forms is required to access the Screen class.

Answer:

You should be able to use the System.Drawing.Screen.* classes to set up multiple windows on each screen. Mind that you don‘t set each window to be maximized, but a properly sized, border less window.

Also - you might want to remember that the total bounds of the multi monitor setup may not always be a rectangle (if you plan to "union" all the bounds to create a window spanning all monitors).

以上是关于WPF 中关于 Screen 的问题(主副屏)的主要内容,如果未能解决你的问题,请参考以下文章

环境问题 - 同局域网内两台笔记本(Win10)实现主副屏幕

环境问题 - 同局域网内两台笔记本(Win10)实现主副屏幕

win10系统bat脚本自启动程序修改壁纸更换主题区分主副屏壁纸

环境问题 - 同局域网内两台笔记本(Win10)实现主副屏幕

关于WPF中关于样式和模板的区别

WPF中关于对前台Xaml中Triggers的一些重要思考。