2009-10-30 2 views
9

Normalerweise verwenden Sie Form.Visible, um zu überprüfen, ob Fenster überhaupt sichtbar ist. Aber manchmal auf dem Bildschirmfenster ist unter anderen Fenstern, so dass es wirklich unsichtbar ist.Wie überprüft man, ob das Fenster wirklich in Windows Forms sichtbar ist?

Also, wie C# Windows Forms einchecken, wenn Fenster wirklich sichtbar ist oder nicht?

Ich möchte dies erreichen: wenn ich auf meiner Tastatur STRG + K klicke und mein Fenster auf meinem Bildschirm sichtbar ist, tut es nichts. Aber wenn es unter anderen Fenstern ist, springt es nach oben (Bring nach vorne).

mit freundlichen Grüßen

Antwort

1

Hm ... seltsame Frage. : P

Vielleicht könnten Sie die Position der Formulare fragen, und wenn zwei Formen interlap (herauszufinden, ihre Koordinaten und eine einfache Methode) überprüfen Sie, ob ein Formular Focus() hat. Wenn es Fokus hat, dann muss andere "unsichtbar" sein (in dem Sinne, dass ein Benutzer es nicht sehen kann, weil es unter dem anderen Formular ist).

Offensichtlich ist diese Methode hacky bestenfalls, aber es ist etwas, mit dem Sie anfangen können zu arbeiten.

2

Um die Frage wie gewünscht zu beantworten, können Sie versuchen, die API-Funktion WindowFromPoint zu verwenden, um das Fenster an verschiedenen Punkten in Ihrem Formular zu finden, und überprüfen Sie, ob es das Handle von dem zurückgibt, was Sie zu diesem Zeitpunkt erwarten.

+0

Dies ist die beste Antwort für mich nach dem Reinigen des Webs und SO. SLaks zur Rettung! Das SO cred spricht für sich. –

4

Sie können Windows-API verwenden, um alle Fenster aufzulisten, ihre Z-Reihenfolge abzurufen und sie mit der Z-Reihenfolge Ihres Fensters zu vergleichen. Ich denke, jemand hat das schon getan here.

0

Sie sollten herausfinden können, ob Ihr Fenster sichtbar ist, indem Sie die OnPaint-Methode überschreiben. Sie möchten die Kontrolle an die Basisklasse übergeben, um die eigentliche Bemalung auszuführen. Sie können jedoch feststellen, ob eine Farbnachricht empfangen wurde. Update: nein, das geht nicht, Sorry!

Im Prinzip sollte die Activate-Methode Ihr Fenster in den Vordergrund bringen, aber in der Praxis habe ich das Problem immer gefunden, wenn andere Prozesse den Eingabefokus haben. Wenn du wirklich möchtest, dass jemand ein Fenster sieht, setze das oberste Bit, aber erwarte, dass sie genervt sind! Ein todsicherer Weg, um Aufmerksamkeit für ein Fenster zu bekommen, ist es zu schließen und wieder zu öffnen, wenn Sie damit durchkommen können.

Eine Möglichkeit, um das zu erreichen, was Sie suchen, ist die Verwendung eines Benachrichtigungssymbols, das die Aufmerksamkeit des Benutzers auf eine Weise weckt, die den Windows-Benutzeroberflächenrichtlinien entspricht.

6

Ich google durch das Netz, aber fand keine gerade Antwort, um zu sehen, ob ein Teil eines Fensters für den Benutzer wirklich sichtbar ist. Ich brauchte tatsächlich eine Möglichkeit, das Formular "zu testen", wenn sich die Maus gerade über dem sichtbaren Teil des Fensters befindet. Ich dachte, dass ich den Code teilen würde, der mehrere Tage dauerte, um zu erreichen:

public class VisibilityTester 
{ 
    private delegate bool CallBackPtr(int hwnd, int lParam); 
    private static CallBackPtr callBackPtr; 

    /// <summary> 
    /// The enumerated pointers of actually visible windows 
    /// </summary> 
    public static List<IntPtr> enumedwindowPtrs = new List<IntPtr>(); 
    /// <summary> 
    /// The enumerated rectangles of actually visible windows 
    /// </summary> 
    public static List<Rectangle> enumedwindowRects = new List<Rectangle>(); 

    /// <summary> 
    /// Does a hit test for specified control (is point of control visible to user) 
    /// </summary> 
    /// <param name="ctrlRect">the rectangle (usually Bounds) of the control</param> 
    /// <param name="ctrlHandle">the handle for the control</param> 
    /// <param name="p">the point to test (usually MousePosition)</param> 
    /// <param name="ExcludeWindow">a control or window to exclude from hit test (means point is visible through this window)</param> 
    /// <returns>boolean value indicating if p is visible for ctrlRect</returns> 
    public static bool HitTest(Rectangle ctrlRect, IntPtr ctrlHandle, Point p, IntPtr ExcludeWindow) 
    { 
     // clear results 
     enumedwindowPtrs.Clear(); 
     enumedwindowRects.Clear(); 

     // Create callback and start enumeration 
     callBackPtr = new CallBackPtr(EnumCallBack); 
     EnumDesktopWindows(IntPtr.Zero, callBackPtr, 0); 

     // Go from last to first window, and substract them from the ctrlRect area 
     Region r = new Region(ctrlRect); 

     bool StartClipping = false; 
     for (int i = enumedwindowRects.Count - 1; i >= 0; i--) 
     { 
      if (StartClipping && enumedwindowPtrs[i] != ExcludeWindow) 
      { 
       r.Exclude(enumedwindowRects[i]); 
      } 

      if (enumedwindowPtrs[i] == ctrlHandle) StartClipping = true; 
     } 

     // return boolean indicating if point is visible to clipped (truly visible) window 
     return r.IsVisible(p); 
    } 

    /// <summary> 
    /// Window enumeration callback 
    /// </summary> 
    private static bool EnumCallBack(int hwnd, int lParam) 
    { 
     // If window is visible and not minimized (isiconic) 
     if (IsWindow((IntPtr)hwnd) && IsWindowVisible((IntPtr)hwnd) && !IsIconic((IntPtr)hwnd)) 
     { 
      // add the handle and windowrect to "found windows" collection 
      enumedwindowPtrs.Add((IntPtr)hwnd); 

      RECT rct; 

      if (GetWindowRect((IntPtr)hwnd, out rct)) 
      { 
       // add rect to list 
       enumedwindowRects.Add(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); 
      } 
      else 
      { 
       // invalid, make empty rectangle 
       enumedwindowRects.Add(new Rectangle(0, 0, 0, 0)); 
      } 
     } 

     return true; 
    } 


    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool IsWindowVisible(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool IsWindow(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool IsIconic(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    private static extern int EnumDesktopWindows(IntPtr hDesktop, CallBackPtr callPtr, int lPar); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); 

    [StructLayout(LayoutKind.Sequential)] 
    private struct RECT 
    { 
     public int Left;  // x position of upper-left corner 
     public int Top;   // y position of upper-left corner 
     public int Right;  // x position of lower-right corner 
     public int Bottom;  // y position of lower-right corner 

     public override string ToString() 
     { 
      return Left + "," + Top + "," + Right + "," + Bottom; 
     } 
    } 
} 
1

konnten Sie auch ..:) Holen Sie die ClickablePoint-Eigenschaft aus dem AutomationElement, das dem Fenster entspricht. Ich bin nicht 100% ig sicher, ob das völlig genau ist, aber .. es hat in 99% der Fälle für mich gearbeitet und ich überprüfe immer noch die anderen 1%, wo das Problem liegt (vielleicht auf meiner Seite oder schlecht Benutzerhandhabung, oder.)

-3

Setzen Sie einfach die Form.AlwaysOnTop Eigenschaft auf true.

+0

Wird nicht helfen, wenn ein anderes Fenster auch die gleiche Eigenschaft hat – Jules

1

Ich habe versucht, SLaks Vorschlag zu implementieren. Obwohl ich es in VB.NET geschrieben habe, nicht C#

Friend Structure PointStruct 
    Public x As Int32 
    Public y As Int32 
End Structure 

<System.Runtime.InteropServices.DllImport("user32.dll")> _ 
Friend Function WindowFromPoint(ByVal Point As PointStruct) As IntPtr 
End Function 

''' <summary> 
''' Checks if a control is actually visible to the user completely 
''' </summary> 
''' <param name="control">The control to check.</param> 
''' <returns>True, if the control is completely visible, false else.</returns> 
''' <remarks>This is not 100% accurate, but feasible enough for my purpose.</remarks> 
Public Function IsControlVisibleToUser(ByVal control As Windows.Forms.Control) As Boolean 
    If Not control.Visible Then Return False 

    Dim bAllPointsVisible As Boolean = True 
    Dim lPointsToCheck As New List(Of Point) 
    'Add the points to check. In this case add the edges and some border points 
    'between the edges. 
    'Strangely, the exact edge points always return the false handle. 
    'So we add a pixel into the control. 
    lPointsToCheck.Add(New Point(control.Left + 1, control.Top + 1)) 
    lPointsToCheck.Add(New Point(control.Right - 1, control.Top + 1)) 
    lPointsToCheck.Add(New Point(control.Right - 1, control.Bottom - 1)) 
    lPointsToCheck.Add(New Point(control.Left + 1, control.Bottom - 1)) 
    lPointsToCheck.Add(New Point(control.Left + control.Width/2, control.Top + 1)) 
    lPointsToCheck.Add(New Point(control.Right - 1, control.Top + control.Height/2)) 
    lPointsToCheck.Add(New Point(control.Right - control.Width/2, control.Bottom - 1)) 
    lPointsToCheck.Add(New Point(control.Left + 1, control.Bottom - control.Height/2)) 
    'lPointsToCheck.Add(New Point(control.Left + control.Width/2, control.Top + control.Height/2)) 

    'Check each point. If all points return the handle of the control, 
    'the control should be visible to the user. 
    For Each oPoint In lPointsToCheck 
     Dim sPoint As New PointStruct() With { 
      .x = oPoint.X, _ 
      .y = oPoint.Y _ 
     } 
     bAllPointsVisible = bAllPointsVisible And (_ 
      (WindowFromPoint(sPoint) = control.Handle) _ 
     ) 
    Next 

    Return bAllPointsVisible 
End Function 
Verwandte Themen