2010-08-13 11 views
6

Ok, quindi il mio previous question non ha prodotto alcuna risposta utile, quindi cercherò di venire da una direzione diversa.HitTest su Windows?

La mia applicazione ha potenzialmente diverse finestre. Dato un punto nelle coordinate dello schermo, ho bisogno di trovare su quale finestra "cade" - cioè trovare la Finestra che è la prima di tutte le finestre che contengono quel punto.

Se fossero Visual s all'interno di una finestra, vorrei usare VisualTreeHelper.HitTest. Ma dal momento che sono finestre diverse, non è chiaro cosa dare come prima argomentazione a quel metodo.

risposta

7

Questo non è possibile utilizzando WPF puro, poiché WPF non espone l'Ordine Z delle sue finestre. In effetti, WPF lavora sodo per mantenere l'illusione che le finestre non si oscurino mai a vicenda.

Se siete disposti fare chiamate Win32, la soluzione è semplice:

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

Se le finestre possono essere trasparenti si dovrebbe anche usare VisualTreeHelper.HitTest nel "dove" clausola di FindWindowAt().

+0

Grazie mille per la risposta. Lo accetterò, poiché è l'unica risposta fino ad ora, e sicuramente funziona, anche se a scapito della richiesta di Full Trust :-(Rimane comunque una domanda: perché sei sicuro che WPF non lo consenta? –

+3

Qualsiasi applicazione Win32 può modificare l'ordine Z utilizzando SetWindowPos. Esistono due modi in cui WPF può ricevere le informazioni sull'ordine Z da Win32: GetTopWindow/GetNextWindow come illustrato in precedenza, oppure gestendo WM_WINDOWPOSCHANGED e lo stato di archiviazione.Non ci sono riferimenti a GetTopWindow negli assembly WPF. L'ispezione degli oggetti nel debugger mostra che WPF non memorizza le informazioni sull'ordine Z. WPF non può dirti cosa non sa da sé. –