代码之家  ›  专栏  ›  技术社区  ›  Fyodor Soikin

跨窗口测试?

  •  6
  • Fyodor Soikin  · 技术社区  · 14 年前

    previous question 没有产生任何有用的答案,所以我会尽量从不同的方向来。

    我的应用程序可能有几个窗口。给定屏幕坐标中的一个点,我需要找到它“落”在哪个窗口上,即找到包含该点的所有窗口中最前面的窗口。

    如果他们是 Visual VisualTreeHelper.HitTest . 但由于它们是不同的窗口,所以不清楚该如何作为该方法的第一个参数。

    1 回复  |  直到 7 年前
        1
  •  8
  •   Drew Noakes    8 年前

    使用纯WPF是不可能的,因为WPF不公开其窗口的Z顺序。事实上,WPF努力保持这样一种错觉,即windows从来不会掩盖彼此。

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

    如果你的窗口可能是透明的,你也应该使用VisualTreeHelper.HitTest测试在FindWindowAt()的where子句中。