Domanda

Normalmente usi Form.Visible per verificare se Window è visibile. Ma a volte sulla finestra dello schermo è sotto altre finestre, quindi è davvero invisibile.

Quindi, come verificare in Windows Forms c # se la finestra è davvero visibile o no?

Vorrei farlo: quando clicco CTRL + K sulla mia tastiera e la mia finestra è visibile sullo schermo non fa nulla. Ma quando è sotto altre finestre si apre in alto (porta in primo piano).

cordiali saluti

È stato utile?

Soluzione

Puoi chiamare Attiva sul modulo per portarlo in primo piano se non lo è già.

Tuttavia, tieni presente che se è attivo un programma diverso, in genere lampeggerà semplicemente il pulsante del desktop (a seconda di dove lo chiami). Questa è la la protezione standard di Windows contro il furto di focus e tu non dovresti provare a aggirarlo .

Altri suggerimenti

Ho cercato su Google attraverso il web, ma non ho trovato nessuna risposta diretta per vedere se una parte di una finestra è veramente visibile all'utente. In realtà avevo bisogno di un modo per "più forte" il modulo, se il mouse è attualmente in cima alla parte visibile della finestra. Ho pensato di condividere il codice che ha richiesto diversi giorni per eseguire:

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;
        }
    }
}

È possibile utilizzare l'API di Windows per enumerare tutte le finestre, recuperarne l'ordine Z e confrontarlo con l'ordine Z della finestra. Penso che qualcuno l'abbia già fatto qui .

Per rispondere alla domanda come richiesto, puoi provare a chiamare WindowFromPoint funzione API per trovare la finestra in vari punti del modulo e verificare se restituisce l'handle di qualunque cosa tu ti aspetti di essere in quel punto.

Hm ... strana domanda. : P

Forse potresti chiedere la posizione dei moduli, e se due moduli si intrecciano (scopri i loro coordini e crea un metodo semplice) controlla se un modulo ha Focus (). Se ha lo stato attivo, allora l'altro deve essere "invisibile" ( nel senso che un utente non può vederlo perché è sotto l'altra forma ).

Ovviamente questo metodo è " nella migliore delle ipotesi , ma è qualcosa con cui puoi iniziare a lavorare.

Puoi anche .. :) ottenere la proprietà ClickablePoint da AutomationElement corrispondente alla finestra. Non sono sicuro al 100% se questo sia completamente accurato però .. ha funzionato nel 99% dei casi per me e sto ancora controllando l'altro 1%, dove si trova il problema (potrebbe essere dalla mia parte o un cattivo utente gestione, oppure.)

Ho attivamente cercato di implementare il suggerimento di SLaks. Anche se l'ho scritto in VB.NET, non in 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

Dovresti essere in grado di scoprire se la tua finestra è visibile sovrascrivendo il metodo OnPaint. Ti consigliamo di passare il controllo alla classe base per eseguire il disegno reale, ma sarai in grado di rilevare se viene ricevuto un messaggio di disegno. Aggiornamento: no, questo non funziona, mi dispiace!

In linea di principio, il metodo Activate dovrebbe portare la tua finestra in primo piano, ma in pratica ho sempre trovato questo problematico se altri processi hanno il focus attivo. Se vuoi davvero che qualcuno veda una finestra, imposta il punto più in alto, ma aspettati che sia infastidito! Un modo infallibile per attirare l'attenzione su una finestra è chiuderla e riaprirla, se riesci a cavartela.

Un modo per ottenere ciò che stai cercando è usare un'icona di notifica, questo attirerà l'attenzione dell'utente in modo conforme alle linee guida dell'interfaccia utente di Windows.

Basta impostare la proprietà Form.AlwaysOnTop su true .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top