WPF:多显示器编程

5

我正在使用 C# 中的 WPF

我想开始进行多显示器编程,这意味着应用程序将在许多具有不同视图的监视器上显示。

我已经在互联网上搜索过,并且得到了使用 Screen.AllScreens[] 的方法,但是我有以下问题:

连接多个显示器到计算机有很多种方式:

情况1: 在笔记本电脑中: 1个笔记本屏幕,1个屏幕连接到VGA端口,1个屏幕连接到HDMI端口...

情况2: 在台式机中: 多个屏幕连接到支持多输出的VGA卡片上

情况3: 多个屏幕连接到Hub HDMI或Hub VGA上,然后Hub连接到PC

我的问题是,Screen.AllScreens[] 支持哪种情况?

还有其他任何方法可以支持所有情况吗?

非常感谢!


2
它应该显示与您在显示设置中设置的逻辑屏幕数量相同,无论它们如何连接。 - Ron Beyer
@RonBeyer:感谢您的回复,您之前尝试过吗? - TTGroup
1
是的,很多次,甚至使用 USB 显示器。 - Ron Beyer
2
这个答案中,Screen.AllScreens似乎有一个警告 - 如果屏幕在程序运行时发生更改,并且在您第一次调用它之后,它可能不会报告正确的屏幕。 - James Thorpe
@JamesThorpe:我会测试那个案例,谢谢! - TTGroup
显示剩余4条评论
1个回答

6

Screens.AllScreens[]是一个WinForms方法,如果我没记错的话,但是是的,它支持你所有的情况(据我所知)。如果我没记错的话,这个WinForms方法在应用程序启动时初始化静态属性,并且如果屏幕在运行时更改,它不会更新。

由于你正在处理WPF,我建议完全避免使用WinForms。相反,编写自己的Screens包装器,调用Win32 API。此外,连接一个事件处理程序来通知您显示设置的更改,例如:

Microsoft.Win32.SystemEvents.DisplaySettingsChanged += new EventHandler(this.SystemEvents_DisplaySettingsChanged);

这是我使用的包装器:

这是我使用的包装器:

/// <summary>
/// This class deals with monitors.
/// </summary>
internal static class Monitors
{
    private static List<Monitors.Screen> Screens = null;

    internal static List<Monitors.Screen> GetScreens()
    {
        Monitors.Screens = new List<Monitors.Screen>();

        var handler = new NativeMethods.DisplayDevicesMethods.EnumMonitorsDelegate(Monitors.MonitorEnumProc);
        NativeMethods.DisplayDevicesMethods.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, handler, IntPtr.Zero); // should be sequential

        return Monitors.Screens;
    }

    private static bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, NativeMethods.DisplayDevicesMethods.RECT rect, IntPtr dwData)
    {
        NativeMethods.DisplayDevicesMethods.MONITORINFO mi = new NativeMethods.DisplayDevicesMethods.MONITORINFO();

        if (NativeMethods.DisplayDevicesMethods.GetMonitorInfo(hMonitor, mi))
        {
            Monitors.Screens.Add(new Monitors.Screen(
                (mi.dwFlags & 1) == 1, // 1 = primary monitor
                mi.rcMonitor.Left, 
                mi.rcMonitor.Top, 
                Math.Abs(mi.rcMonitor.Right - mi.rcMonitor.Left), 
                Math.Abs(mi.rcMonitor.Bottom - mi.rcMonitor.Top)));
        }

        return true;
    }

    /// <summary>
    /// Represents a display device on a single system.
    /// </summary>
    internal sealed class Screen
    {
        /// <summary>
        /// Initializes a new instance of the Screen class.
        /// </summary>
        /// <param name="primary">A value indicating whether the display is the primary screen.</param>
        /// <param name="x">The display's top corner X value.</param>
        /// <param name="y">The display's top corner Y value.</param>
        /// <param name="w">The width of the display.</param>
        /// <param name="h">The height of the display.</param>
        internal Screen(bool primary, int x, int y, int w, int h)
        {
            this.IsPrimary = primary;
            this.TopX = x;
            this.TopY = y;
            this.Width = w;
            this.Height = h;
        }

        /// <summary>
        /// Gets a value indicating whether the display device is the primary monitor.
        /// </summary>
        internal bool IsPrimary { get; private set; }

        /// <summary>
        /// Gets the display's top corner X value.
        /// </summary>
        internal int TopX { get; private set; }

        /// <summary>
        /// Gets the display's top corner Y value.
        /// </summary>
        internal int TopY { get; private set; }

        /// <summary>
        /// Gets the width of the display.
        /// </summary>
        internal int Width { get; private set; }

        /// <summary>
        /// Gets the height of the display.
        /// </summary>
        internal int Height { get; private set; }
    }
}

internal static class NativeMethods
{
    /// <summary>
    /// Methods for retrieving display devices.
    /// </summary>
    internal static class DisplayDevicesMethods
    {
        internal delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, NativeMethods.DisplayDevicesMethods.RECT rect, IntPtr dwData);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, EnumMonitorsDelegate lpfnEnum, IntPtr dwData);

        /// <summary>
        /// Retrieves information about a display monitor.
        /// </summary>
        /// <param name="hmonitor">A handle to the display monitor of interest.</param>
        /// <param name="info">A pointer to a MONITORINFO or MONITORINFOEX structure that receives information about the specified display monitor.</param>
        /// <returns>If the function succeeds, the return value is nonzero.</returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetMonitorInfo(IntPtr hmonitor, [In, Out] NativeMethods.DisplayDevicesMethods.MONITORINFO info);

        /// <summary>
        /// The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        internal struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        /// <summary>
        /// The MONITORINFO structure contains information about a display monitor.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
        internal class MONITORINFO
        {
            internal int cbSize = Marshal.SizeOf(typeof(NativeMethods.DisplayDevicesMethods.MONITORINFO));
            internal NativeMethods.DisplayDevicesMethods.RECT rcMonitor = new NativeMethods.DisplayDevicesMethods.RECT();
            internal NativeMethods.DisplayDevicesMethods.RECT rcWork = new NativeMethods.DisplayDevicesMethods.RECT();
            internal int dwFlags;
        }
    }
}

谢谢,非常好用。 - Greg Cobb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接