我知道我可以通过使用获得主屏幕的大小
System.Windows.SystemParameters.PrimaryScreenWidth;
System.Windows.SystemParameters.PrimaryScreenHeight;
但是,如何获取当前屏幕的大小?(多屏幕用户并不总是使用主屏幕,并且并非所有屏幕都使用相同的分辨率,对吗?)
能够从XAML访问大小很好,但是从代码(C#)进行访问就足够了。
Answers:
我从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; }
}
}
哥们 这只会给您工作区的宽度和高度
System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
这将基于窗口的左上角为您提供当前屏幕,只需调用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));
}
}
}
花点时间浏览SystemParameters成员。
VirtualScreenWidth
VirtualScreenHeight
这些甚至考虑到屏幕的相对位置。
仅在两个监视器上进行过测试。
为什么不只使用它呢?
var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
System.Windows.Forms.Screen
以应对与设备无关的像素
如果您熟悉使用System.Windows.Forms类,则可以添加引用System.Windows.Forms类到项目中:
解决方案资源管理器->引用->添加引用...- > (程序集:框架) ->向下滚动并检查System.Windows.Forms程序集->确定。
现在您可以使用System.Windows.Forms添加;像以前一样在wpf项目中声明和使用屏幕。
我还需要当前的屏幕尺寸,特别是工作区域,该尺寸返回不包括任务栏宽度的矩形。
我用它来重新定位窗口,该窗口向右下方打开到鼠标所在的位置。由于窗口很大,因此在许多情况下,它超出了屏幕范围。下面的代码是基于@ej答案:这会给你当前屏幕...。所不同的是,我还展示了我的重新定位算法,我认为这实际上就是重点。
编码:
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>
我了解需求。关键是,有WPF方法可以获取这些值-但是,是的,其中一个贡献者是正确的,而不是直接的。解决方案不是获得所有这些解决方法,而是根据干净的设计和开发更改初始方法。
A)将初始主窗口设置为屏幕
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);
}
如果您使用任何全屏窗口(具有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作为孩子,因此您应该可以将其与任何内容一起使用。)