165

What I am looking for is the equivalent of System.Windows.SystemParameters.WorkArea for the monitor that the window is currently on.

Clarification: The window in question is WPF, not WinForm.

Ghasem
  • 14,455
  • 21
  • 138
  • 171
chilltemp
  • 8,854
  • 8
  • 41
  • 46
  • 2
    Changed accepted answer to reflect the best way to do this from WPF. System.Windows.SystemParameters.* – chilltemp May 25 '10 at 15:33
  • 1
    The obsession with not using a WinForms namespace seems strange to me, it doesn't gain you anything; instead, it leaves you without the tools you need to properly solve the problem. – Jeff Yates Sep 30 '11 at 13:34
  • 4
    For me, it's not about WinForms vs. WPF. It's about learning something new. I can't decide which way is better if I don't learn both ways. – chilltemp Oct 03 '11 at 15:17
  • 3
    Well, in this scenario there is no "both ways" as there's only one way to do this, which is to use the WinForms stuff. – Jeff Yates Oct 03 '11 at 17:00
  • @Jeff Yates: You are correct. I dug up the original project that I asked this question for, and found that I used the PrimaryScreen* properties. They solved my needs of the day, but not the actual question I asked. Sorry for the run-around; I've changed the accepted answer accordingly. – chilltemp Oct 13 '11 at 16:45

13 Answers13

168

Screen.FromControl, Screen.FromPoint and Screen.FromRectangle should help you with this. For example in WinForms it would be:

class MyForm : Form
{
  public Rectangle GetScreen()
  {
    return Screen.FromControl(this).Bounds;
  }
}

I don't know of an equivalent call for WPF. Therefore, you need to do something like this extension method.

static class ExtensionsForWPF
{
  public static System.Windows.Forms.Screen GetScreen(this Window window)
  {
    return System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(window).Handle);
  }
}
Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
  • 1
    Perhaps my tagging didn’t make it clear that I am using WPF windows, not WinForms. I do not have the System.Windows.Forms.dll referenced, and it wouldn’t work anyway as WPF has its own inheritance tree. – chilltemp Oct 31 '08 at 17:25
  • 1
    You're welcome. My apologies for not getting straight to the answer - I had to investigate what was available in WPF before I updated my post. – Jeff Yates Nov 03 '08 at 18:37
  • This works to put a window on the right-hand edge: var bounds = this.GetScreen().WorkingArea; this.Left = bounds.Right - this.Width; But it requires references to System.Windows.Forms and System.Drawing, which is not ideal. – Anthony Apr 03 '09 at 08:42
  • Why is that not ideal? Those assemblies are likely to be present when WPF is present as they are .NET 2.0 and below. – Jeff Yates Apr 03 '09 at 12:04
  • 1
    @devios Beware that this call isn't DPI-aware; you'll need to do calculations. – Lynn Crumbling Jul 30 '15 at 19:03
  • 6
    In my VS 2015 WPF app targeting .NET 4.5 on my 4-monitor system on Windows 10 Pro (v10.0.14393) with `window` on the monitor _above_ my Primary's (e.g., its `Top < 0`), `FromHandle` returned the `Screen` for my Primary monitor's (even though `window` was _completely_ within the Secondary monitor)!?! Sigh. It looks like I'll have to search the `Screen.AllScreens` Array myself. Why can't things "just work"?!? Arrrrgh. – Tom Apr 28 '17 at 09:05
  • There remains 1 problem with this. Point units are not the same. Here, for example, Screen.Bounds is (1920,1080), a fullscreen WPF window considers itself as (1936,1096). I guess this is what Lynn means by DPI. – Alan Baljeu Sep 19 '19 at 16:51
67

You can use this to get desktop workspace bounds of the primary screen:

System.Windows.SystemParameters.WorkArea

This is also useful for getting just the size of the primary screen:

System.Windows.SystemParameters.PrimaryScreenWidth System.Windows.SystemParameters.PrimaryScreenHeight

Filip Skakun
  • 31,624
  • 6
  • 74
  • 100
Pyttroll
  • 861
  • 7
  • 6
  • 24
    I'm confused... This seems only to return the primary screen dimensions. I want to know the dimensions of the screen the window is currently at... – VitalyB Jan 16 '11 at 11:50
  • 2
    this does not answer the question and even if you just want to get the size of the primary display the SystemParameters (in WPF) are incorrect. they return device independent units and *not* pixels. for a better implementation see this answer: http://stackoverflow.com/questions/254197/how-can-i-get-the-active-screen-dimensions/254241#254241 – Patrick Klug Sep 29 '11 at 23:28
  • 2
    PrimaryScreenHeight/Width worked exactly as expected, and MSDN has the following on them: "Gets a value that indicates the screen height, in pixels, of the primary display monitor." WorkArea does not specifically say pixels, but the documentation and usage examples leads me to believe me that it is also in pixels. Do you have a link to something indicating the use of device independent units? – chilltemp Oct 03 '11 at 15:37
36

Also you may need:

to get the combined size of all monitors and not one in particular.

Samuel Jack
  • 32,712
  • 16
  • 118
  • 155
742
  • 3,009
  • 3
  • 23
  • 18
  • 2
    **Hint:** To use it, one needs to add the reference `PresentationFramework.dll` and `using System.Windows;` – Matt May 04 '18 at 07:35
22

Adding a solution that doesn't use WinForms but NativeMethods instead. First you need to define the native methods needed.

public static class NativeMethods
{
    public const Int32 MONITOR_DEFAULTTOPRIMERTY = 0x00000001;
    public const Int32 MONITOR_DEFAULTTONEAREST = 0x00000002;


    [DllImport( "user32.dll" )]
    public static extern IntPtr MonitorFromWindow( IntPtr handle, Int32 flags );


    [DllImport( "user32.dll" )]
    public static extern Boolean GetMonitorInfo( IntPtr hMonitor, NativeMonitorInfo lpmi );


    [Serializable, StructLayout( LayoutKind.Sequential )]
    public struct NativeRectangle
    {
        public Int32 Left;
        public Int32 Top;
        public Int32 Right;
        public Int32 Bottom;


        public NativeRectangle( Int32 left, Int32 top, Int32 right, Int32 bottom )
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }
    }


    [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Auto )]
    public sealed class NativeMonitorInfo
    {
        public Int32 Size = Marshal.SizeOf( typeof( NativeMonitorInfo ) );
        public NativeRectangle Monitor;
        public NativeRectangle Work;
        public Int32 Flags;
    }
}

And then get the monitor handle and the monitor info like this.

        var hwnd = new WindowInteropHelper( this ).EnsureHandle();
        var monitor = NativeMethods.MonitorFromWindow( hwnd, NativeMethods.MONITOR_DEFAULTTONEAREST );

        if ( monitor != IntPtr.Zero )
        {
            var monitorInfo = new NativeMonitorInfo();
            NativeMethods.GetMonitorInfo( monitor, monitorInfo );

            var left = monitorInfo.Monitor.Left;
            var top = monitorInfo.Monitor.Top;
            var width = ( monitorInfo.Monitor.Right - monitorInfo.Monitor.Left );
            var height = ( monitorInfo.Monitor.Bottom - monitorInfo.Monitor.Top );
        }
R.Rusev
  • 1,111
  • 15
  • 19
  • 1
    Can you get the real screen size if there are scale factor of your windows (100% / 125% / 150% / 200%) ? – Kiquenet Jul 23 '19 at 12:55
14

Add on to ffpf

Screen.FromControl(this).Bounds
faulty
  • 8,117
  • 12
  • 44
  • 61
13

Beware of the scale factor of your windows (100% / 125% / 150% / 200%). You can get the real screen size by using the following code:

SystemParameters.FullPrimaryScreenHeight
SystemParameters.FullPrimaryScreenWidth
aDoubleSo
  • 1,128
  • 9
  • 19
  • 5
    That's for the primary screen - what if your app window is on a virtual (extended) screen (i.e. you have one or two external monitors attached to your PC)? – Matt May 04 '18 at 08:10
5

I wanted to have the screen resolution before opening the first of my windows, so here a quick solution to open an invisible window before actually measuring screen dimensions (you need to adapt the window parameters to your window in order to ensure that both are openend on the same screen - mainly the WindowStartupLocation is important)

Window w = new Window();
w.ResizeMode = ResizeMode.NoResize;
w.WindowState = WindowState.Normal;
w.WindowStyle = WindowStyle.None;
w.Background = Brushes.Transparent;
w.Width = 0;
w.Height = 0;
w.AllowsTransparency = true;
w.IsHitTestVisible = false;
w.WindowStartupLocation = WindowStartupLocation.Manual;
w.Show();
Screen scr = Screen.FromHandle(new WindowInteropHelper(w).Handle);
w.Close();
Richard Ev
  • 52,939
  • 59
  • 191
  • 278
Andre
  • 109
  • 2
  • 1
3

I needed to set the maximum size of my window application. This one could changed accordingly the application is is been showed in the primary screen or in the secondary. To overcome this problem e created a simple method that i show you next:

/// <summary>
/// Set the max size of the application window taking into account the current monitor
/// </summary>
public static void SetMaxSizeWindow(ioConnect _receiver)
{
    Point absoluteScreenPos = _receiver.PointToScreen(Mouse.GetPosition(_receiver));

    if (System.Windows.SystemParameters.VirtualScreenLeft == System.Windows.SystemParameters.WorkArea.Left)
    {
        //Primary Monitor is on the Left
        if (absoluteScreenPos.X <= System.Windows.SystemParameters.PrimaryScreenWidth)
        {
            //Primary monitor
            _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.WorkArea.Width;
            _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.WorkArea.Height;
        }
        else
        {
            //Secondary monitor
            _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.VirtualScreenWidth - System.Windows.SystemParameters.WorkArea.Width;
            _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.VirtualScreenHeight;
        }
    }

    if (System.Windows.SystemParameters.VirtualScreenLeft < 0)
    {
        //Primary Monitor is on the Right
        if (absoluteScreenPos.X > 0)
        {
            //Primary monitor
            _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.WorkArea.Width;
            _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.WorkArea.Height;
        }
        else
        {
            //Secondary monitor
            _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.VirtualScreenWidth - System.Windows.SystemParameters.WorkArea.Width;
            _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.VirtualScreenHeight;
        }
    }
}
VMAtm
  • 27,943
  • 17
  • 79
  • 125
3

This is a "Center Screen DotNet 4.5 solution", using SystemParameters instead of System.Windows.Forms or My.Compuer.Screen: Since Windows 8 has changed the screen dimension calculation, the only way it works for me looks like that (Taskbar calculation included):

Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
    Dim BarWidth As Double = SystemParameters.VirtualScreenWidth - SystemParameters.WorkArea.Width
    Dim BarHeight As Double = SystemParameters.VirtualScreenHeight - SystemParameters.WorkArea.Height
    Me.Left = (SystemParameters.VirtualScreenWidth - Me.ActualWidth - BarWidth) / 2
    Me.Top = (SystemParameters.VirtualScreenHeight - Me.ActualHeight - BarHeight) / 2         
End Sub

Center Screen WPF XAML

Nasenbaer
  • 4,810
  • 11
  • 53
  • 86
  • installer setup in WPF? – Kiquenet Jul 23 '19 at 12:52
  • The main question is about screen position. Like Msi installer, Innosetup or others, I created my own installer with CPU-check, Permission check, driver verification and much more, very simple to use. Thats the screenshot about. – Nasenbaer Aug 07 '19 at 14:55
2

WinForms

For multi-monitor setups you will also need account for the X and Y position:

Rectangle activeScreenDimensions = Screen.FromControl(this).Bounds;
this.Size = new Size(activeScreenDimensions.Width + activeScreenDimensions.X, activeScreenDimensions.Height + activeScreenDimensions.Y);
Community
  • 1
  • 1
user3424480
  • 362
  • 2
  • 6
  • 19
1

in C# winforms I have got start point (for case when we have several monitor/diplay and one form is calling another one) with help of the following method:

private Point get_start_point()
    {
        return
            new Point(Screen.GetBounds(parent_class_with_form.ActiveForm).X,
                      Screen.GetBounds(parent_class_with_form.ActiveForm).Y
                      );
    }
Oleg Bash
  • 19
  • 1
1

This debugging code should do the trick well:

You can explore the properties of the Screen Class

Put all displays in an array or list using Screen.AllScreens then capture the index of the current display and its properties.

enter image description here

C# (Converted from VB by Telerik - Please double check)

        {
    List<Screen> arrAvailableDisplays = new List<Screen>();
    List<string> arrDisplayNames = new List<string>();

    foreach (Screen Display in Screen.AllScreens)
    {
        arrAvailableDisplays.Add(Display);
        arrDisplayNames.Add(Display.DeviceName);
    }

    Screen scrCurrentDisplayInfo = Screen.FromControl(this);
    string strDeviceName = Screen.FromControl(this).DeviceName;
    int idxDevice = arrDisplayNames.IndexOf(strDeviceName);

    MessageBox.Show(this, "Number of Displays Found: " + arrAvailableDisplays.Count.ToString() + Constants.vbCrLf + "ID: " + idxDevice.ToString() + Constants.vbCrLf + "Device Name: " + scrCurrentDisplayInfo.DeviceName.ToString + Constants.vbCrLf + "Primary: " + scrCurrentDisplayInfo.Primary.ToString + Constants.vbCrLf + "Bounds: " + scrCurrentDisplayInfo.Bounds.ToString + Constants.vbCrLf + "Working Area: " + scrCurrentDisplayInfo.WorkingArea.ToString + Constants.vbCrLf + "Bits per Pixel: " + scrCurrentDisplayInfo.BitsPerPixel.ToString + Constants.vbCrLf + "Width: " + scrCurrentDisplayInfo.Bounds.Width.ToString + Constants.vbCrLf + "Height: " + scrCurrentDisplayInfo.Bounds.Height.ToString + Constants.vbCrLf + "Work Area Width: " + scrCurrentDisplayInfo.WorkingArea.Width.ToString + Constants.vbCrLf + "Work Area Height: " + scrCurrentDisplayInfo.WorkingArea.Height.ToString, "Current Info for Display '" + scrCurrentDisplayInfo.DeviceName.ToString + "' - ID: " + idxDevice.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Information);
}

VB (Original code)

 Dim arrAvailableDisplays As New List(Of Screen)()
    Dim arrDisplayNames As New List(Of String)()

    For Each Display As Screen In Screen.AllScreens
        arrAvailableDisplays.Add(Display)
        arrDisplayNames.Add(Display.DeviceName)
    Next

    Dim scrCurrentDisplayInfo As Screen = Screen.FromControl(Me)
    Dim strDeviceName As String = Screen.FromControl(Me).DeviceName
    Dim idxDevice As Integer = arrDisplayNames.IndexOf(strDeviceName)

    MessageBox.Show(Me,
                    "Number of Displays Found: " + arrAvailableDisplays.Count.ToString & vbCrLf &
                    "ID: " & idxDevice.ToString + vbCrLf &
                    "Device Name: " & scrCurrentDisplayInfo.DeviceName.ToString + vbCrLf &
                    "Primary: " & scrCurrentDisplayInfo.Primary.ToString + vbCrLf &
                    "Bounds: " & scrCurrentDisplayInfo.Bounds.ToString + vbCrLf &
                    "Working Area: " & scrCurrentDisplayInfo.WorkingArea.ToString + vbCrLf &
                    "Bits per Pixel: " & scrCurrentDisplayInfo.BitsPerPixel.ToString + vbCrLf &
                    "Width: " & scrCurrentDisplayInfo.Bounds.Width.ToString + vbCrLf &
                    "Height: " & scrCurrentDisplayInfo.Bounds.Height.ToString + vbCrLf &
                    "Work Area Width: " & scrCurrentDisplayInfo.WorkingArea.Width.ToString + vbCrLf &
                    "Work Area Height: " & scrCurrentDisplayInfo.WorkingArea.Height.ToString,
                    "Current Info for Display '" & scrCurrentDisplayInfo.DeviceName.ToString & "' - ID: " & idxDevice.ToString, MessageBoxButtons.OK, MessageBoxIcon.Information)

Screens List

Daniel Santos
  • 188
  • 2
  • 15
0

I Know it's an old question, but others may get some value from this

int formWidth = form.Width;
int formHeight = form.Height;
int formTop = form.Top;
int formLeft = form.Left;

Screen screen = Screen.PrimaryScreen;
Rectangle rect = screen.Bounds;
int screenWidth = rect.Width;
int screenHeight = rect.Height;
int screenTop = rect.Top;
int screenLeft = rect.Left;
HemmaRoyD
  • 79
  • 1
  • 9