Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HitTest across Windows?

Tags:

wpf

hittest

Ok, so my previous question did not produce any useful answers, so I'll try to come from a different direction.

My application has, potentially, several windows. Given a point in screen coordinates, I need to find which window it "falls" onto - i.e. find the Window that is foremost of all windows containing said point.

If they were Visuals inside one window, I would use VisualTreeHelper.HitTest. But since they are different windows, it's not clear what to give as the first argument to that method.

like image 218
Fyodor Soikin Avatar asked Aug 13 '10 01:08

Fyodor Soikin


1 Answers

This is not possible using pure WPF, as WPF does not expose the Z Order of its windows. In fact, WPF works hard to maintain the illusion that windows never actually obscure one another.

If you're willing make Win32 calls, the solution is 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); 

If your windows may be transparent you should also use VisualTreeHelper.HitTest in the "where" clause of FindWindowAt().

like image 117
Ray Burns Avatar answered Nov 11 '22 11:11

Ray Burns