F A Fernández
F A Fernández

Reputation: 134

Select monitor to show WPF application

I'm working on a WPF application, and I want to select the monitor where to display the window. My .NET version is 8.0, SO is Windows and Version is 7.0.

I'm trying to apply the [Mostlytech][2] steps, but simply it's just not working for me, the window is always displayed on the same monitor independent of the selected AllScreens parameter.:

My C#:

  public MainWindow () {

      this.WindowStartupLocation = WindowStartupLocation.Manual;
      Debug.Assert(System.Windows.Forms.SystemInformation.MonitorCount > 1);
      System.Drawing.Rectangle workingArea = System.Windows.Forms.Screen.AllScreens[0].WorkingArea;

      this.Left = workingArea.Left;
      this.Top = workingArea.Top;
      this.Width = workingArea.Width;
      this.Height = workingArea.Height;
      this.WindowState = WindowState.Maximized;
      this.WindowStyle = WindowStyle.None;
      this.Topmost = true;
      this.Show();

      InitializeComponent();
      SetLists();
      // Rest of the Program.

  }

My XAML header:

<Window x:Class="_4913_TV.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_4913_TV"
        mc:Ignorable="d"
        WindowState="Maximized"
        WindowStyle="None"
        Title="MainWindow"
        Cursor="None"
        Width="4096"
        Height="2160"
        KeyDown="KeyedKey">

The System.Drawing.Rectangle workingArea = System.Windows.Forms.Screen.AllScreens[0].WorkingArea;it seems to correctly contain the information from my monitors.

[![enter image description here][3]][3]

Thanks very much for your support.

NOTE

For the generated executable to be scaled to the necessary resolution, it must always be compiled on the machine or with the screen to be used. For example, if you have a 70'' 4k TV in your home, surely your production with a 55'' 4k screen will look stretched. To fix this, make sure that when you compile the executable you have the screen/TV that will be used for the application connected to your PC. This way, when you start your application using the generated ".exe" file, your application will correctly adoipt the screen size.

Upvotes: 0

Views: 158

Answers (1)

emoacht
emoacht

Reputation: 3591

The code snippet you linked won't make the window maximized correctly when the monitors' DPI are not default (100%).

Instead, I would like to suggest a different approach. The code below will manipulate the position and size of maximized window so that it will fit the working area of a monitor specified with index number given by command-line argument.

using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace WpfApp2;

public partial class MainWindow : Window
{
    public int Index { get; private set; }

    public MainWindow()
    {
        InitializeComponent();

        // Get index number from command-line argument.
        Index = int.TryParse(Environment.GetCommandLineArgs().LastOrDefault(), out int i) && (i > 0) ? i : 0;

        nint handle = new WindowInteropHelper(this).EnsureHandle();
        var source = HwndSource.FromHwnd(handle);
        source.AddHook(new HwndSourceHook(WndProc));
    }

    private const int WM_GETMINMAXINFO = 0x0024;

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        public int x;
        public int y;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MINMAXINFO
    {
        public POINT ptReserved;
        public POINT ptMaxSize;
        public POINT ptMaxPosition;
        public POINT ptMinTrackSize;
        public POINT ptMaxTrackSize;
    }

    private nint WndProc(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled)
    {
        switch (msg)
        {
            case WM_GETMINMAXINFO:
                var screens = System.Windows.Forms.Screen.AllScreens;
                if (Index < screens.Length)
                {
                    var workingArea = screens[Index].WorkingArea;

                    var info = Marshal.PtrToStructure<MINMAXINFO>(lParam);

                    info.ptMaxPosition.x = workingArea.X;
                    info.ptMaxPosition.y = workingArea.Y;
                    info.ptMaxSize.x = workingArea.Width;
                    info.ptMaxSize.y = workingArea.Height;

                    Marshal.StructureToPtr(info, lParam, true);
                }
                break;
        }
        return nint.Zero;
    }
}
<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="400" Height="300"
        WindowStartupLocation="Manual"
        WindowState="Maximized"
        Topmost="True">
    <Grid>

    </Grid>
</Window>

It requires the following sections to be included in the application manifest.

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>
    <!-- Windows 10 -->
    <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
  </application>
</compatibility>

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
  </windowsSettings>
</application>

Upvotes: 1

Related Questions