2010-08-13 9 views
6

Ok, donc mon previous question n'a pas donné de réponses utiles, donc je vais essayer de venir d'une autre direction.HitTest sur Windows?

Mon application a, potentiellement, plusieurs fenêtres. Étant donné un point dans les coordonnées de l'écran, j'ai besoin de trouver sur quelle fenêtre il "tombe" - c'est-à-dire trouver la Fenêtre qui est la plus importante de toutes les fenêtres contenant ce point.

Si elles étaient Visual s à l'intérieur d'une fenêtre, j'utiliserais VisualTreeHelper.HitTest. Mais comme ce sont des fenêtres différentes, on ne sait pas quoi donner comme premier argument à cette méthode.

Répondre

7

Ceci n'est pas possible avec WPF pur, car WPF n'expose pas l'ordre Z de ses fenêtres. En fait, WPF travaille dur pour maintenir l'illusion que les fenêtres ne s'obscurcissent jamais les unes les autres.

Si vous êtes prêt faire des appels Win32, la solution est 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 vos fenêtres peuvent être transparents, vous devez également utiliser VisualTreeHelper.HitTest dans le « où » clause de FindWindowAt().

+0

Merci beaucoup pour votre réponse. Je vais l'accepter, car c'est la seule réponse à ce jour, et cela fonctionne vraiment, ne serait-ce que au détriment de la confiance totale :-(Une question subsiste cependant: pourquoi êtes-vous sûr que WPF ne le permet pas? –

+3

Toute application Win32 peut modifier l'ordre Z à l'aide de SetWindowPos WPF peut recevoir ces informations Z Order de Win32: GetTopWindow/GetNextWindow comme indiqué ci-dessus, ou en manipulant WM_WINDOWPOSCHANGED et en stockant l'état.Il n'y a aucune référence à GetTopWindow dans les assemblys WPF. L'inspection des objets dans le débogueur montre que WPF ne stocke pas non plus d'informations sur la commande Z. WPF ne peut pas vous dire ce qu'il ne sait pas lui-même. –