如何在 WPF 中获取当前屏幕的大小?
Posted
技术标签:
【中文标题】如何在 WPF 中获取当前屏幕的大小?【英文标题】:How to get the size of the current screen in WPF? 【发布时间】:2010-12-28 00:07:42 【问题描述】:我知道我可以通过使用获得主屏幕的大小
System.Windows.SystemParameters.PrimaryScreenWidth;
System.Windows.SystemParameters.PrimaryScreenHeight;
但是如何获取当前屏幕的大小呢? (多屏用户并不总是使用主屏幕,而且并非所有屏幕都使用相同的分辨率,对吧?)
如果能够从 XAML 访问大小会很好,但是从代码 (C#) 中这样做就足够了。
【问题讨论】:
定义“当前”。一个窗口可以同时出现在多个屏幕上。 【参考方案1】:我从 System.Windows.Forms 围绕屏幕创建了一个小包装,目前一切正常... 不过,不确定“设备独立像素”。
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;
【讨论】:
感谢这个伟大的小包装器,请注意,当我与 WPF 3.5 一起使用时,global::Rect 需要转换为纯 Rect。 我喜欢这个。当然它需要一些工作,但我不希望找到 100% 的解决方案。 效果很好。我只是扩展了 GetRect 方法以返回与设备无关的像素中的 Rect: private Rect GetRect(Rectangle value) var pixelWidthFactor = SystemParameters.WorkArea.Width / this.screen.WorkingArea.Width; var pixelHeightFactor = SystemParameters.WorkArea.Height / this.screen.WorkingArea.Height; return new Rect X = value.X * pixelWidthFactor, Y = value.Y * pixelHeightFactor, Width = value.Width * pixelWidthFactor, Height = value.Height * pixelHeightFactor ; 我相信添加来自@JürgenBayer 的代码将进一步改善您的答案。我遇到了与设备无关像素的问题,Jürgen 的代码解决了这个问题。谢谢你们。 @Jürgen:我相信你的方法只适用于非常特殊的情况。如果“this.screen”的纵横比与主监视器不同(您的方法始终将其用作参考而不是当前监视器),您将错误地获得不同的宽度和高度比例因子,从而导致错误的屏幕尺寸。如果当前屏幕的 DPI 设置与主屏幕不同,则边界将全部错误。在我的系统上,返回的 Rect 的每个值都是(非常)不正确的。【参考方案2】:这里的伙计。这只会给你工作区的宽度和高度
System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
【讨论】:
"获取主显示器上工作区的大小。" - 不是我想要的......【参考方案3】:这将为您提供基于窗口左上角的当前屏幕,只需调用 this.CurrentScreen() 即可获取当前屏幕上的信息。
using System.Windows;
using System.Windows.Forms;
namespace Common.Helpers
public static class WindowHelpers
public static Screen CurrentScreen(this Window window)
return Screen.FromPoint(new System.Drawing.Point((int)window.Left,(int)window.Top));
【讨论】:
这将根据您调用辅助函数的窗口的左上角位置返回当前屏幕。但是,根据我的回答分数,我一定错过了这个问题的一些东西。 @jim-balter 投票了 - 实际上这是最好的答案,我需要屏幕才能获得工作区,然后确保我的对话框没有超出界限,我会发布我的解决方案在这里。感谢 E.J.快速中肯的答案。 ^ 奇怪的评论。【参考方案4】:我还需要当前屏幕尺寸,特别是工作区,它返回的矩形不包括任务栏宽度。
我使用它来重新定位一个窗口,该窗口向右打开并向下打开到鼠标所在的位置。由于窗口相当大,在许多情况下它超出了屏幕边界。以下代码基于@e-j 答案:This will give you the current screen...。不同之处在于我还展示了我的重新定位算法,我认为这实际上是重点。
代码:
using System.Windows;
using System.Windows.Forms;
namespace MySample
public class WindowPostion
/// <summary>
/// This method adjust the window position to avoid from it going
/// out of screen bounds.
/// </summary>
/// <param name="topLeft">The requiered possition without its offset</param>
/// <param name="maxSize">The max possible size of the window</param>
/// <param name="offset">The offset of the topLeft postion</param>
/// <param name="margin">The margin from the screen</param>
/// <returns>The adjusted position of the window</returns>
System.Drawing.Point Adjust(System.Drawing.Point topLeft, System.Drawing.Point maxSize, int offset, int margin)
Screen currentScreen = Screen.FromPoint(topLeft);
System.Drawing.Rectangle rect = currentScreen.WorkingArea;
// Set an offset from mouse position.
topLeft.Offset(offset, offset);
// Check if the window needs to go above the task bar,
// when the task bar shadows the HUD window.
int totalHight = topLeft.Y + maxSize.Y + margin;
if (totalHight > rect.Bottom)
topLeft.Y -= (totalHight - rect.Bottom);
// If the screen dimensions exceed the hight of the window
// set it just bellow the top bound.
if (topLeft.Y < rect.Top)
topLeft.Y = rect.Top + margin;
int totalWidth = topLeft.X + maxSize.X + margin;
// Check if the window needs to move to the left of the mouse,
// when the HUD exceeds the right window bounds.
if (totalWidth > rect.Right)
// Since we already set an offset remove it and add the offset
// to the other side of the mouse (2x) in addition include the
// margin.
topLeft.X -= (maxSize.X + (2 * offset + margin));
// If the screen dimensions exceed the width of the window
// don't exceed the left bound.
if (topLeft.X < rect.Left)
topLeft.X = rect.Left + margin;
return topLeft;
一些解释:
1) topLeft - position of the top left at the desktop (works
for multi screens - with different aspect ratio).
Screen1 Screen2
─ ┌───────────────────┐┌───────────────────┐ Screen3
▲ │ ││ │┌─────────────────┐ ─
│ │ ││ ││ ▼- │ ▲
1080 │ │ ││ ││ │ │
│ │ ││ ││ │ │ 900
▼ │ ││ ││ │ ▼
─ └──────┬─────┬──────┘└──────┬─────┬──────┘└──────┬────┬─────┘ ─
─┴─────┴─ ─┴─────┴─ ─┴────┴─
│◄─────────────────►││◄─────────────────►││◄───────────────►│
1920 1920 1440
If the mouse is in Screen3 a possible value might be:
topLeft.X=4140 topLeft.Y=195
2) offset - the offset from the top left, one value for both
X and Y directions.
3) maxSize - the maximal size of the window - including its
size when it is expanded - from the following example
we need maxSize.X = 200, maxSize.Y = 150 - To avoid the expansion
being out of bound.
Non expanded window:
┌──────────────────────────────┐ ─
│ Window Name [X]│ ▲
├──────────────────────────────┤ │
│ ┌─────────────────┐ │ │ 100
│ Text1: │ │ │ │
│ └─────────────────┘ │ │
│ [▼] │ ▼
└──────────────────────────────┘ ─
│◄────────────────────────────►│
200
Expanded window:
┌──────────────────────────────┐ ─
│ Window Name [X]│ ▲
├──────────────────────────────┤ │
│ ┌─────────────────┐ │ │
│ Text1: │ │ │ │
│ └─────────────────┘ │ │ 150
│ [▲] │ │
│ ┌─────────────────┐ │ │
│ Text2: │ │ │ │
│ └─────────────────┘ │ ▼
└──────────────────────────────┘ ─
│◄────────────────────────────►│
200
4) margin - The distance the window should be from the screen
work-area - Example:
┌─────────────────────────────────────────────────────────────┐ ─
│ │ ↕ Margin
│ │ ─
│ │
│ │
│ │
│ ┌──────────────────────────────┐ │
│ │ Window Name [X]│ │
│ ├──────────────────────────────┤ │
│ │ ┌─────────────────┐ │ │
│ │ Text1: │ │ │ │
│ │ └─────────────────┘ │ │
│ │ [▲] │ │
│ │ ┌─────────────────┐ │ │
│ │ Text2: │ │ │ │
│ │ └─────────────────┘ │ │
│ └──────────────────────────────┘ │ ─
│ │ ↕ Margin
├──────────────────────────────────────────────────┬──────────┤ ─
│[start] [♠][♦][♣][♥] │en│ 12:00 │
└──────────────────────────────────────────────────┴──────────┘
│◄─►│ │◄─►│
Margin Margin
* Note that this simple algorithm will always want to leave the cursor
out of the window, therefor the window will jumps to its left:
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ ▼-┌──────────────┐ │ ┌──────────────┐▼- │
│ │ Window [X]│ │ │ Window [X]│ │
│ ├──────────────┤ │ ├──────────────┤ │
│ │ ┌───┐ │ │ │ ┌───┐ │ │
│ │ Val: │ │ │ -> │ │ Val: │ │ │ │
│ │ └───┘ │ │ │ └───┘ │ │
│ └──────────────┘ │ └──────────────┘ │
│ │ │ │
├──────────────────────┬──────────┤ ├──────────────────────┬──────────┤
│[start] [♠][♦][♣] │en│ 12:00 │ │[start] [♠][♦][♣] │en│ 12:00 │
└──────────────────────┴──────────┘ └──────────────────────┴──────────┘
If this is not a requirement, you can add a parameter to just use
the margin:
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ ▼-┌──────────────┐ │ ┌─▼-───────────┐ │
│ │ Window [X]│ │ │ Window [X]│ │
│ ├──────────────┤ │ ├──────────────┤ │
│ │ ┌───┐ │ │ │ ┌───┐ │ │
│ │ Val: │ │ │ -> │ │ Val: │ │ │ │
│ │ └───┘ │ │ │ └───┘ │ │
│ └──────────────┘ │ └──────────────┘ │
│ │ │ │
├──────────────────────┬──────────┤ ├──────────────────────┬──────────┤
│[start] [♠][♦][♣] │en│ 12:00 │ │[start] [♠][♦][♣] │en│ 12:00 │
└──────────────────────┴──────────┘ └──────────────────────┴──────────┘
* Supports also the following scenarios:
1) Screen over screen:
┌─────────────────┐
│ │
│ │
│ │
│ │
└─────────────────┘
┌───────────────────┐
│ │
│ ▼- │
│ │
│ │
│ │
└──────┬─────┬──────┘
─┴─────┴─
2) Window bigger than screen hight or width
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ │ │ ┌──────────────┐ │
│ │ │ │ Window [X]│ │
│ ▼-┌────────────│─┐ │ ├──────────────┤ ▼- │
│ │ Window [│]│ │ │ ┌───┐ │ │
│ ├────────────│─┤ -> │ │ Val: │ │ │ │
│ │ ┌───┐│ │ │ │ └───┘ │ │
│ │ Val: │ ││ │ │ │ ┌───┐ │ │
│ │ └───┘│ │ │ │ Val: │ │ │ │
├──────────────────────┬──────────┤ │ ├──────────────────────┬──────────┤
│[start] [♠][♦][♣] │en│ 12:00 │ │ │[start] [♠][♦][♣] │en│ 12:00 │
└──────────────────────┴──────────┘ │ └──────────────────────┴──────────┘
│ ┌───┐ │ │ └───┘ │
│ Val: │ │ │ └──────────────┘
│ └───┘ │
└──────────────┘
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ │ │ │
│ │ │ ┌───────────────────────────────│───┐
│ ▼-┌──────────────────────────│────────┐ │ │ W▼-dow │[X]│
│ │ Window │ [X]│ │ ├───────────────────────────────│───┤
│ ├──────────────────────────│────────┤ │ │ ┌───┐ ┌───┐ ┌─┤─┐ │
│ │ ┌───┐ ┌───┐ │ ┌───┐ │ -> │ │ Val: │ │ Val: │ │ Val: │ │ │ │
│ │ Val: │ │ Val: │ │ Va│: │ │ │ │ │ └───┘ └───┘ └─┤─┘ │
│ │ └───┘ └───┘ │ └───┘ │ │ └───────────────────────────────│───┘
├──────────────────────┬──────────┤────────┘ ├──────────────────────┬──────────┤
│[start] [♠][♦][♣] │en│ 12:00 │ │[start] [♠][♦][♣] │en│ 12:00 │
└──────────────────────┴──────────┘ └──────────────────────┴──────────┘
我别无选择,只能使用代码格式(否则空格
会丢失)。
最初这在上面的代码中显示为<remark><code>...</code></remark>
【讨论】:
我觉得你需要金牌来解释和说明 那幅插图简直……太美了!!【参考方案5】:据我所知,没有原生 WPF 函数可以获取当前监视器的尺寸。相反,您可以 PInvoke 本机 multiple display monitors functions,将它们包装在托管类中,并公开您需要从 XAML 中使用它们的所有属性。
【讨论】:
这正是我所担心的——需要 P/Invoke 这些东西或以某种方式访问 System.Windows.Forms.Screen。这样做时,我总是需要计算“与设备无关的像素”......不过,谢谢。 是的...也许 SystemParameters.ConvertPixel() 函数也会对您有所帮助。它是内部的,但 Reflector 不在乎 :)...【参考方案6】:为什么不直接使用这个?
var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
【讨论】:
屏幕是 Windows.Forms 而不是 WPF - 但这是一个起点。如果您查看我当时使用的解决方案 (***.com/a/2118993/180156),这正是我所做的 - 但是我包装了System.Windows.Forms.Screen
以应对与设备无关的像素【参考方案7】:
花点时间浏览一下 SystemParameters 成员。
VirtualScreenWidth
VirtualScreenHeight
这些甚至考虑了屏幕的相对位置。
仅使用两台显示器进行测试。
【讨论】:
dana - 我没有对此进行测试,但 VirtualScreen* 不会返回所有屏幕的完整尺寸吗? - 我特别需要一个屏幕的大小(当前窗口所在的那个)。 VirtualScreen 好像是指所有屏幕的大小 一个我的这返回了我所有 4 个屏幕的总大小。【参考方案8】:我很欣赏这是一个老问题,但看到 WPF 仍然没有提供一种“开箱即用”的好方法,上面的答案似乎有点过于复杂,希望你能在下面找到解决方案比较容易消化..
WPF 友好,即返回与设备无关的单位(不是 WinForm 样式的像素) 支持不同 DPI 的显示器 适合任何尺寸/位置的任务栏 System.Windows.Window 上的扩展方法。享受:)
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using Point = System.Drawing.Point;
namespace ClrVpin.Shared
public static class WindowExtensions
public static Rect GetCurrentScreenWorkArea(this Window window)
var screen = Screen.FromPoint(new Point((int) window.Left, (int) window.Top));
var dpiScale = VisualTreeHelper.GetDpi(window);
return new Rect Width = screen.WorkingArea.Width / dpiScale.DpiScaleX, Height = screen.WorkingArea.Height / dpiScale.DpiScaleY;
【讨论】:
很好的解决方案!【参考方案9】:如果您熟悉使用 System.Windows.Forms 类,那么您只需将 System.Windows.Forms 类的引用添加到您的项目中:
解决方案资源管理器 -> 参考文献 -> 添加参考文献... -> (程序集:框架) -> 向下滚动并检查 System.Windows.Forms 程序集 -> OK。
现在您可以像以前一样在您的 wpf 项目中添加 using System.Windows.Forms; 语句并使用 screen。
【讨论】:
这是迄今为止最简单的解决方案。我想知道 - 除了添加一个相当大的程序集之外,还有什么好的理由不这样做吗?【参考方案10】:我看到这篇文章,发现没有一个答案能完全捕捉到我想要做的事情。我有一台分辨率为 3840x2160 的笔记本电脑和两台分辨率为 1920x1080 的显示器。为了在我的 WPF 应用程序中获得正确的监视器大小,我必须 make the application DPI aware。然后我使用 Win32 API 来获取显示器大小。
我首先将窗口移动到我想从中获取大小的监视器上。然后通过获取应用程序 MainWindow 的 hwnd (不必是主窗口,但我的应用程序只有一个窗口)和一个 IntPtr 到监视器。然后我创建了 MONITORINFOEX 结构的一个新实例并调用了 GetMonitorInfo 方法。
MONITORINFOEX 结构同时具有工作区和屏幕的全分辨率,因此您可以返回您需要的任何一个。这也将允许您省略对 System.Windows.Forms 的引用(假设您在应用程序中不需要它)。我使用 System.Windows.Forms.Screen 的 .NET Framework Reference Source 来提出这个解决方案。
public System.Drawing.Size GetMonitorSize()
var window = System.Windows.Application.Current.MainWindow;
var hwnd = new WindowInteropHelper(window).EnsureHandle();
var monitor = NativeMethods.MonitorFromWindow(hwnd, NativeMethods.MONITOR_DEFAULTTONEAREST);
NativeMethods.MONITORINFO info = new NativeMethods.MONITORINFO();
NativeMethods.GetMonitorInfo(new HandleRef(null, monitor), info);
return info.rcMonitor.Size;
internal static class NativeMethods
public const Int32 MONITOR_DEFAULTTONEAREST = 0x00000002;
[DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(IntPtr handle, Int32 flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool GetMonitorInfo(HandleRef hmonitor, MONITORINFO info);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
public class MONITORINFO
internal int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
internal RECT rcMonitor = new RECT();
internal RECT rcWork = new RECT();
internal int dwFlags = 0;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
public int left;
public int top;
public int right;
public int bottom;
public RECT(int left, int top, int right, int bottom)
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
public RECT(System.Drawing.Rectangle r)
left = r.Left;
top = r.Top;
right = r.Right;
bottom = r.Bottom;
public static RECT FromXYWH(int x, int y, int width, int height) => new RECT(x, y, x + width, y + height);
public System.Drawing.Size Size => new System.Drawing.Size(right - left, bottom - top);
【讨论】:
【参考方案11】:我理解这些要求。 问题是,有用于获取这些值的 WPF 方法 - 但是,是的,其中一位贡献者是正确的,而不是直接的。 解决方案不是获得所有这些变通方法,而是根据干净的设计和开发更改初始方法。
A) 将初始主窗口设置为 Screen
B) 获取 ActualWindow 的值,包括大量有用的 WPF 方法
C) 您可以根据需要添加任意数量的 Windows 以实现您想要的行为,例如可调整大小、最小化等等……但现在您始终可以访问加载和渲染的屏幕
请注意以下示例,周围有一些代码使得有必要使用这种方法,但是它应该可以工作(它会给你屏幕每个角落的分数): 单显示器、双显示器和不同分辨率的工作示例(在原始主窗口类中):
InitializeComponent();
[…]
ActualWindow.AddHandler(Window.LoadedEvent, new RoutedEventHandler(StartUpScreenLoaded));
路由事件:
private void StartUpScreenLoaded(object sender, RoutedEventArgs e)
Window StartUpScreen = sender as Window;
// Dispatcher Format B:
Dispatcher.Invoke(new Action(() =>
// Get Actual Window on Loaded
StartUpScreen.InvalidateVisual();
System.Windows.Point CoordinatesTopRight = StartUpScreen.TranslatePoint(new System.Windows.Point((StartUpScreen.ActualWidth), (0d)), ActualWindow);
System.Windows.Point CoordinatesBottomRight = StartUpScreen.TranslatePoint(new System.Windows.Point((StartUpScreen.ActualWidth), (StartUpScreen.ActualHeight)), ActualWindow);
System.Windows.Point CoordinatesBottomLeft = StartUpScreen.TranslatePoint(new System.Windows.Point((0d), (StartUpScreen.ActualHeight)), ActualWindow);
// Set the Canvas Top Right, Bottom Right, Bottom Left Coordinates
System.Windows.Application.Current.Resources["StartUpScreenPointTopRight"] = CoordinatesTopRight;
System.Windows.Application.Current.Resources["StartUpScreenPointBottomRight"] = CoordinatesBottomRight;
System.Windows.Application.Current.Resources["StartUpScreenPointBottomLeft"] = CoordinatesBottomLeft;
), DispatcherPriority.Loaded);
【讨论】:
【参考方案12】:如果您使用任何全屏窗口(具有其WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None
),您可以将其内容包装在System.Windows.Controls.Canvas
中,如下所示:
<Canvas Name="MyCanvas" Width="auto" Height="auto">
...
</Canvas>
然后,您可以使用MyCanvas.ActualWidth
和MyCanvas.ActualHeight
来获取当前屏幕的分辨率,同时考虑到 DPI 设置并以设备独立为单位。
它不会像最大化窗口本身那样添加任何边距。
(Canvas 接受 UIElement
s 作为子级,因此您应该能够将它用于任何内容。)
【讨论】:
【参考方案13】:XAML WindowStartupLocation="CenterOwner"
中的屏幕居中窗口然后调用 WindowLoaded()
double ScreenHeight = 2 * (Top + 0.5 * Height);
【讨论】:
谢谢 MIkesl - 你救了我的遗憾.. 干杯【参考方案14】:double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
double screenhight= System.Windows.SystemParameters.PrimaryScreenHeight;
【讨论】:
与前面的答案一样,这仅适用于 primary 屏幕。我需要当前屏幕。【参考方案15】:它适用于
this.Width = System.Windows.SystemParameters.VirtualScreenWidth;
this.Height = System.Windows.SystemParameters.VirtualScreenHeight;
在 2 台显示器上测试。
【讨论】:
如果您查看 2010 年 5 月 18 日 15:52 的答案 - 这与您的答案完全相同,您会看到VirtualScreen
跨越所有屏幕 - 所以如果您拥有多个屏幕!以上是关于如何在 WPF 中获取当前屏幕的大小?的主要内容,如果未能解决你的问题,请参考以下文章
WPF:如何在调整大小后保持 ListBox SelectedItem 可见?