HitTest across Windows?
Ok, so my previous question did not produce any useful answers, so I'll try t开发者_如何学Goo 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 Visual
s 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.
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().
精彩评论