To get information about displays connected using WinUI 3, the simplest I can think of is to use
Nugget package: WindowsDisplayApi
Info here
It's a older package, however it works really well.
Once installed, you can do for example:
using System.Text.RegularExpressions;
using CommunityToolkit.Mvvm.ComponentModel;
using WindowsDisplayAPI;
namespace EasyDisplay.ViewModels;
public partial class DemoViewModel : ObservableObject
{
[ObservableProperty]
private string displayName = string.Empty;
[ObservableProperty]
private string friendly = string.Empty;
[ObservableProperty]
private string resolution = string.Empty;
[ObservableProperty]
private string position = string.Empty;
public DemoViewModel()
{
foreach (Display display in Display.GetDisplays())
{
DisplayName = display.DisplayName;
Friendly = GetFriendly(display.DisplayName);
Resolution = GetResolution(display);
Position = GetPosition(display);
}
}
private static string GetFriendly(string value)
{
return Regex.Replace(value, @"[^A-Za+Z0-9 ]", "");
}
private static string GetResolution(Display display)
{
return display.CurrentSetting.Resolution.Width.ToString() + " x " + display.CurrentSetting.Resolution.Height.ToString();
}
private static string GetPosition(Display display)
{
return display.CurrentSetting.Position.X.ToString() + " x " + display.CurrentSetting.Position.Y.ToString();
}
}
and more as per below:
A second option using the Win32 APIs is available here, and may give you more functionalities.
Option 3 - Using P/Invoke
Step 1: Define the Supporting Structures and P/Invoke Signatures
First, define the necessary structs and P/Invoke signatures for EnumDisplayMonitors and GetMonitorInfo.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
// Define the RECT structure
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
// Define the MONITORINFOEX structure
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MONITORINFOEX
{
public int Size = Marshal.SizeOf(typeof(MONITORINFOEX));
public RECT Monitor;
public RECT Work;
public uint Flags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName = string.Empty;
}
// Define the MonitorDetails class
public class MonitorDetails
{
public string DeviceName;
public bool IsPrimary;
public int Height;
public int Width;
public RECT MonitorArea;
public RECT WorkArea;
}
// Define the delegate for EnumDisplayMonitors callback
public delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
// P/Invoke signatures
public class NativeMethods
{
[DllImport("user32.dll")]
public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetMonitorInfo(IntPtr hMonitor, [In, Out] MONITORINFOEX lpmi);
}
Step 2: Implement GetAllMonitors Method
The GetAllMonitors method you've already defined calls the native EnumDisplayMonitors function, iterating through each monitor and collecting details into a list.
public static List<MonitorDetails> GetAllMonitors()
{
var monitors = new List<MonitorDetails>();
MonitorEnumProc callback = (IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData) =>
{
MONITORINFOEX mi = new MONITORINFOEX();
if (NativeMethods.GetMonitorInfo(hMonitor, mi))
{
var monitorInfo = new MonitorDetails
{
DeviceName = mi.DeviceName,
IsPrimary = (mi.Flags & 1) != 0, // MONITORINFOF_PRIMARY
Height = mi.Monitor.Bottom - mi.Monitor.Top,
Width = mi.Monitor.Right - mi.Monitor.Left,
MonitorArea = mi.Monitor,
WorkArea = mi.Work,
};
monitors.Add(monitorInfo);
}
return true;
};
NativeMethods.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, IntPtr.Zero);
return monitors;
}
Cursor
: You need to subclass the UI Element for this to work source. Or you use reflection... but that's not a great way to do things. – Psychodiagnosis