51

I am developing an application that remembers the user's preferences as to where the form was last located on the screen. In some instances the user will have it on a secondary screen, and then fire the app up later without the second screen (sometimes having the form appear off screen). Other times the user will change their resolution resulting in a similar effect.

I was hoping to do this checking in the Form_Shown event handler. Basically I want to determine whether the form is completely off screen so I can re-position it.

Any advice?

LarsTech
  • 80,625
  • 14
  • 153
  • 225
Cody
  • 3,734
  • 2
  • 24
  • 29
  • I should mention that I'm aware I can perform some tricky logic by getting the screen resolution, size and location of the form, however I was hoping for something a little more elegant. – Cody Jun 12 '09 at 14:50
  • You really think its more elegant to position the form, check to see if its outside the resolution / size and then reposition it? A more elegant solution would be to check to see if you are GOING to position it off the screen BEFORE you do. – Allen Rice Aug 28 '09 at 18:57

8 Answers8

70

Check with this function if Form is fully on screen:

public bool IsOnScreen( Form form )
{
   Screen[] screens = Screen.AllScreens;
   foreach( Screen screen in screens )
   {
      Rectangle formRectangle = new Rectangle( form.Left, form.Top, 
                                               form.Width, form.Height );

      if( screen.WorkingArea.Contains( formRectangle ) )
      {
         return true;
      }
   }

   return false;
}

Checking only top left point if it's on screen:

public bool IsOnScreen( Form form )
{
   Screen[] screens = Screen.AllScreens;
   foreach( Screen screen in screens )
   {
      Point formTopLeft = new Point( form.Left, form.Top );

      if( screen.WorkingArea.Contains( formTopLeft ) )
      {
         return true;
      }
   }

   return false;
}
Marcus Mangelsdorf
  • 2,852
  • 1
  • 30
  • 40
Andrija
  • 14,037
  • 18
  • 60
  • 87
  • I forgot how to get Form rectangle other way around, but I hope this helps – Andrija Jun 12 '09 at 14:58
  • That looks really neat, and I didn't know that functionality existed. One question though: Won't that still return false if the window is only partially off screen? The question asks for completely offscreen. – Martin Harris Jun 12 '09 at 14:59
  • Thank you Andrija. This looks like it will work with some modifications. I haven't tried it yet, but I believe I saw a screen.WorkingArea.Intersects or something similar while experimenting yesterday that will be able to tell if it is completely off screen. – Cody Jun 12 '09 at 15:06
  • 1
    I just played with it. If you add the line screen.WorkingArea.Intersect(formRectangle); right above the if statement if (screen.WorkingArea.Contains(formRectangle)) it will determine if the form is completely off screen or not. Thanks again Andrija! – Cody Jun 12 '09 at 15:27
  • See Also: Sean's answer below for a few extra details that should get it working 100% – Cody Mar 11 '11 at 17:05
  • Have compiled all answers into complete answer below. – CrazyTim Apr 13 '15 at 00:53
  • Why do we instantiate a new Rectangle/Point with each loop? Can't we instantiate it before the loop and use that one new Rectangle/Point? – Michael Gorsich Nov 02 '20 at 06:07
22

Combining all the solutions above with the "IntersectsWith"-method and LINQ-extensions give us in short:

public bool IsOnScreen(Form form) 
{
   // Create rectangle
   Rectangle formRectangle = new Rectangle(form.Left, form.Top, form.Width, form.Height); 

   // Test
   return Screen.AllScreens.Any(s => s.WorkingArea.IntersectsWith(formRectangle));
}
Matthias Loerke
  • 2,177
  • 1
  • 14
  • 8
  • Couldn't this be even more simplified using [`Form.ClientRectangle`](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.clientrectangle.aspx) – Carsten Apr 22 '13 at 14:24
  • 1
    It would fit for most purposes, although it would not include the whole form. Control.ClientRectangle in MSDN:"The client area of a control is the bounds of the control, minus the nonclient elements such as scroll bars, borders, title bars, and menus." (http://msdn.microsoft.com/en-us/library/system.windows.forms.control.clientrectangle.aspx) – Matthias Loerke Oct 01 '13 at 07:37
  • 3
    You can use [`Form.DesktopBounds`](http://msdn.microsoft.com/en-us/library/system.windows.forms.form.desktopbounds(v=vs.110).aspx) – Dan Bechard Jun 27 '14 at 17:52
11

Complete solution here (based on all answers). I have added a parameter MinPercentOnScreen where at least this % of pixels must be visible across all screens/displays. So if this returns false you will need to move the window's position back to default.

// Return True if a certain percent of a rectangle is shown across the total screen area of all monitors, otherwise return False.
public bool IsOnScreen(System.Drawing.Point RecLocation, System.Drawing.Size RecSize, double MinPercentOnScreen = 0.2)
{
    double PixelsVisible = 0;
    System.Drawing.Rectangle Rec = new System.Drawing.Rectangle(RecLocation, RecSize);

    foreach (Screen Scrn in Screen.AllScreens)
    {
        System.Drawing.Rectangle r = System.Drawing.Rectangle.Intersect(Rec, Scrn.WorkingArea);
        // intersect rectangle with screen
        if (r.Width != 0 & r.Height != 0)
        {
            PixelsVisible += (r.Width * r.Height);
            // tally visible pixels
        }
    }
    return PixelsVisible >= (Rec.Width * Rec.Height) * MinPercentOnScreen;
}

Implementation:

return IsOnScreen(this.Location, this.Size);
CrazyTim
  • 6,695
  • 6
  • 34
  • 55
4

Old thread, but still helpful! Cody and Andrija- thanks for the code. I had to make a couple of minor adjustments: Instead of screen.WorkingArea.Intersect(formRectangle); I used formRectangle.Intersect(screen.WorkingArea); since Intersect() replaces its object with the intersection. If the form is completely off the screen, formRectangle after the intersection is (0,0,0,0), and Contains() returns true. So I also check to see if formRectangle Top, Left, Width and Height are not all 0 before returning true. Now the code returns true if any part of the form is on screen, and false if no part is on screen.

Sean
  • 41
  • 1
  • 1
    Thanks Sean! Is there some way we can incorporate this answer into Andrija's for a complete answer? – Cody Mar 11 '11 at 17:05
1

For WPF (based on Matthias Loerkes answer)

Add a reference to System.Windows.Forms and System.Drawing.

//using System.Windows.Forms;

public bool IsOnScreen(Window window)
{
   var windowRect = new System.Drawing.Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height);
   return Screen.AllScreens.Any(s => s.WorkingArea.IntersectsWith(windowRect));
}
salle55
  • 2,101
  • 2
  • 25
  • 27
1

None of these work if a monitor happens to be off. The Screen.AllScreens function will always return the number of screens even if one is off.

Tom
  • 527
  • 1
  • 8
  • 28
  • At least for DisplayPort everything is OK. `Screen.AllScreens` will start to return only 1 monitor. And my resue code works fine. It moves a form window to a primary monitor. Tested! But many thanks for the tip. Possibly some video connectors will create troubles in this case. – it3xl Aug 13 '19 at 15:16
0

A one-liner solution using DesktopBounds:

Array.Exists(Screen.AllScreens, screen => screen.WorkingArea.Contains(DesktopBounds))
glopes
  • 4,038
  • 3
  • 26
  • 29
0

Check the screens resolution before you position the window. That will allow you to figure out if you where going to place it outside the bounds of the resolution, before you actually do it.

Allen Rice
  • 19,068
  • 14
  • 83
  • 115