Search code examples
c#wpfwindowsdpimultiple-monitors

Fullscreen WPF window on a MS Windows system with multiple Monitors and different DPI settings


I have a Windows 11 system with 2 monitors:

  • One 4k monitor with scale factor of 150% and
  • One FullHD monitor on scale factor 100% (Of course this needs to work with differnt system settings too)

I want to show a new WPF Window on the other monitor - meaning on the monitor my main app is currently not being displayed on. So if my main window is on the 4k monitor then I want to show the new window on the FullHD monitor.

The new windows should be showing a fullscreen view of my webcam. But having different DPI settings makes it hard to show a fullscreen window in the correct position and size.

My Window XAML is straight forward and looks like this

<Window
    x:Class="MyApp.Fullscreen"
    x:ClassModifier="internal"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="800"
    Height="600"
    AllowsTransparency="False"
    Background="Black"
    ResizeMode="NoResize"
    ShowInTaskbar="False"
    Topmost="True"
    WindowStyle="None">
    <Grid>
        <Image Name="WebCam" />
    </Grid>
</Window>

I initialize it like this

 var allSystemScreens = System.Windows.Forms.Screen.AllScreens;
 var otherScreen = DetermineOtherScreen(allSystemScreens);

 var window = new Fullscreen();
 window.WindowStartupLocation = WindowStartupLocation.Manual;

 window.Left = otherScreen.WorkingArea.Left;
 window.Top = otherScreen.WorkingArea.Top;
 window.Width = otherScreen.WorkingArea.Width;
 window.Height = otherScreen.WorkingArea.Height;

 window.Show();

But it does not work. It does not show the window fully on the monitor or is way bigger than the monitor and is reaching into the second one.

I played around with the values from the WorkingArea. But it never works.

My app is DPI per-monitor-aware. I tried to apply the scale factor that I read from the system but no matter what values I use - it is never correct positioned or sized.

How to do it correctly? Or is there an easier or better way to achieve this? Maybe without using the WindowStartupLocation.Manual.


Solution

  • OK, so instead of using the WorkingArea property, which may not take into account the DPI scaling, we can use the Bounds property of the monitor to calculate the correct position and size, in my new suggestion, I'm using the Bounds property of the monitor, which represents the entire monitor area, including any taskbars or other system elements and by dividing the Bounds values by the DPI scale factor, I can ensure that the position and size are calculated correctly for the specific monitor's DPI scaling!

    Additionally, I've added window.WindowState = WindowState.Maximized; to set the window to fullscreen mode.

    var otherScreen = DetermineOtherScreen(allSystemScreens);
    
    var otherScreenScaleFactor = VisualTreeHelper.GetDpi(window);
    double otherScreenScale = otherScreenScaleFactor.DpiScaleX;
    
    double left = otherScreen.Bounds.Left / otherScreenScale;
    double top = otherScreen.Bounds.Top / otherScreenScale;
    double width = otherScreen.Bounds.Width / otherScreenScale;
    double height = otherScreen.Bounds.Height / otherScreenScale;
        
    window.Left = left;
    window.Top = top;
    window.Width = width;
    window.Height = height;
    
    window.WindowState = WindowState.Maximized;