2010-08-13 10 views
6

Ok, also hat meine previous question keine brauchbaren Antworten ergeben, also werde ich versuchen, aus einer anderen Richtung zu kommen.HitTest über Windows?

Meine Anwendung hat möglicherweise mehrere Fenster. Bei einem Punkt in Bildschirmkoordinaten muss ich herausfinden, auf welches Fenster er "fällt" - d. H. Das Fenster finden, das an erster Stelle aller Fenster steht, die diesen Punkt enthalten. Wenn sie Visual s in einem Fenster waren, würde ich VisualTreeHelper.HitTest verwenden. Da es sich jedoch um verschiedene Fenster handelt, ist nicht klar, was als erstes Argument für diese Methode angegeben werden soll.

Antwort

7

Dies ist mit reinem WPF nicht möglich, da WPF die Z-Reihenfolge seiner Fenster nicht freigibt. Tatsächlich arbeitet WPF hart daran, die Illusion aufrecht zu erhalten, dass sich Fenster niemals gegenseitig verschleiern.

Wenn Sie bereit sind, machen Win32-Aufrufe, die Lösung ist einfach:

public Window FindWindowAt(Point screenPoint) // WPF units (96dpi), not device units 
{ 
    return (
    from win in SortWindowsTopToBottom(Application.Current.Windows.OfType<Window>()) 
    where new Rect(win.Left, win.Top, win.Width, win.Height).Contains(screenPoint) 
    select win 
).FirstOrDefault(); 
} 

public static IEnumerable<Window> SortWindowsTopToBottom(IEnumerable<Window> unsorted) 
{ 
    var byHandle = unsorted.ToDictionary(win => 
    ((HwndSource)PresentationSource.FromVisual(win)).Handle); 

    for(IntPtr hWnd = GetTopWindow(IntPtr.Zero); hWnd!=IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT)) 
    if(byHandle.ContainsKey(hWnd)) 
     yield return byHandle[hWnd]; 
} 

const uint GW_HWNDNEXT = 2; 
[DllImport("User32")] static extern IntPtr GetTopWindow(IntPtr hWnd); 
[DllImport("User32")] static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd); 

Wenn Sie Ihre Fenster transparent sein können Sie auch VisualTreeHelper.HitTest in der „where“ Klausel FindWindowAt() verwenden soll.

+0

Vielen Dank für Ihre Antwort. Ich werde es akzeptieren, da es die einzige Antwort ist, und es funktioniert definitiv, wenn nur auf Kosten von Full Trust :-(Eine Frage bleibt jedoch: Warum genau sind Sie sicher, dass WPF dies nicht erlaubt? –

+3

Jede beliebige Win32-Anwendung kann die Z-Reihenfolge mithilfe von SetWindowPos ändern Es gibt zwei Möglichkeiten, wie WPF diese Z-Bestellinformationen von Win32 erhalten kann: GetTopWindow/GetNextWindow wie oben gezeigt oder WM_WINDOWPOSCHANGED verarbeiten und Status speichern Es gibt keine Verweise auf GetTopWindow in den WPF-Assemblys. Das Überprüfen von Objekten im Debugger zeigt, dass WPF keine Z-Order-Informationen speichert. WPF kann Ihnen nicht sagen, was es selbst nicht weiß. –

Verwandte Themen