【问题标题】:HitTest across Windows?跨 Windows 的 HitTest?
【发布时间】:2010-08-13 01:40:50
【问题描述】:

好的,所以我的previous question 没有提供任何有用的答案,所以我会尝试从不同的方向来。

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

如果他们在一个窗口内是Visuals,我会使用VisualTreeHelper.HitTest。但由于它们是不同的窗口,因此不清楚该方法的第一个参数是什么。

【问题讨论】:

    标签: wpf hittest


    【解决方案1】:

    使用纯 WPF 无法做到这一点,因为 WPF 不公开其窗口的 Z 顺序。事实上,WPF 努力保持窗口从不真正相互遮挡的错觉。

    如果你愿意进行 Win32 调用,解决方案很简单:

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

    如果您的窗口可能是透明的,您还应该在 FindWindowAt() 的“where”子句中使用 VisualTreeHelper.HitTest。

    【讨论】:

    • 非常感谢您的回答。我会接受它,因为它是迄今为止唯一的答案,而且它肯定有效,如果只是以要求完全信任为代价:-( 然而,还有一个问题:你为什么确定 WPF 不允许这样做?
    • 任何 Win32 应用程序都可以使用 SetWindowPos 更改 Z 顺序。 WPF 可以通过两种方式从 Win32 接收此 Z 顺序信息:如上所示的 GetTopWindow/GetNextWindow,或者通过处理 WM_WINDOWPOSCHANGED 和存储状态。 WPF 程序集中没有对 GetTopWindow 的引用。在调试器中检查对象表明 WPF 也不存储 Z 顺序信息。 WPF 不能告诉你它自己不知道什么。
    猜你喜欢
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多