2010-08-13 16 views
6

Ok, entonces mi previous question no produjo ninguna respuesta útil, así que trataré de tomar una dirección diferente.HitTest en Windows?

Mi aplicación tiene, potencialmente, varias ventanas. Dado un punto en las coordenadas de la pantalla, necesito encontrar en qué ventana "cae", es decir, encontrar la ventana que es la más importante de todas las ventanas que contienen dicho punto.

Si fueran Visual s dentro de una ventana, usaría VisualTreeHelper.HitTest. Pero dado que son ventanas diferentes, no está claro qué dar como primer argumento para ese método.

Respuesta

7

Esto no es posible usando WPF puro, ya que WPF no expone el orden Z de sus ventanas. De hecho, WPF trabaja arduamente para mantener la ilusión de que las ventanas nunca se oscurecen entre sí.

Si estás dispuesto hacer llamadas de Win32, la solución es simple:

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

Si sus ventanas pueden ser transparentes también se debe utilizar VisualTreeHelper.HitTest en el "donde" cláusula de FindWindowAt().

+0

Muchas gracias por su respuesta. Lo aceptaré, ya que es la única respuesta hasta el momento, y definitivamente funciona, aunque sea a expensas de requerir plena confianza :-(Sin embargo, queda una pregunta: ¿por qué estás tan seguro de que WPF no permite esto? –

+3

Cualquier aplicación Win32 puede cambiar el orden Z utilizando SetWindowPos. Hay dos maneras en que WPF podría recibir esta Z Solicitar información desde Win32: GetTopWindow/GetNextWindow como se muestra arriba, o manejando WM_WINDOWPOSCHANGED y almacenando el estado. No hay referencias a GetTopWindow en los ensamblajes de WPF. La inspección de objetos en el depurador muestra que WPF no almacena información de pedido Z. WPF no puede decirle lo que no sabe. –