WPF-在屏幕外渲染网格上模拟鼠标事件

WPF-在屏幕外渲染网格上模拟鼠标事件,wpf,events,input,simulation,off-screen,Wpf,Events,Input,Simulation,Off Screen,我正在使用多个元素按钮、文本框等渲染WPF网格。。。到位图,该位图随后用作Direct3D场景中3D曲面的纹理。对于用户交互,我从2D鼠标光标位置创建一条3D光线到3D场景中,找到与gui曲面的交点。所以我知道用户在哪里点击了WPF网格,但从那里我被卡住了: 当WPF元素实际上没有显示在打开的窗口中,而是呈现在屏幕外时,如何在WPF元素上模拟鼠标事件 最近,我研究了UIAutomation和RaiseEvent,但它们用于将事件发送到单个元素,而不是整个可视化树。手动遍历树并在光标位置查找元素将

我正在使用多个元素按钮、文本框等渲染WPF网格。。。到位图,该位图随后用作Direct3D场景中3D曲面的纹理。对于用户交互,我从2D鼠标光标位置创建一条3D光线到3D场景中,找到与gui曲面的交点。所以我知道用户在哪里点击了WPF网格,但从那里我被卡住了:

当WPF元素实际上没有显示在打开的窗口中,而是呈现在屏幕外时,如何在WPF元素上模拟鼠标事件

最近,我研究了UIAutomation和RaiseEvent,但它们用于将事件发送到单个元素,而不是整个可视化树。手动遍历树并在光标位置查找元素将是一种选择,但我还没有找到一种方法来准确地做到这一点。VisualTreeHelper.HitTest是一个很好的开始,但是它没有找到TextBox,而是找到TextBoxView,而不是ListBox,它找到了一个边框

编辑:返回HitTestResultBehavior。在HitTest的结果回调中继续让我在给定点遍历所有元素。我现在可以将鼠标事件发送到所有这些元素,但MouseEventArgs对象的值是真实鼠标的值。因此,我必须创建一个自定义鼠标设备,这显然是不可能的

PointHitTestParameters p = new PointHitTestParameters(new Point(
    ((Vector2)hit).X * sourceElement.ActualWidth, 
    (1 - ((Vector2)hit).Y) * sourceElement.ActualHeight));
VisualTreeHelper.HitTest(sourceElement,
     new HitTestFilterCallback(delegate(DependencyObject o)
     {
         return HitTestFilterBehavior.Continue;
     }),
     new HitTestResultCallback(delegate(HitTestResult r)
     {
         UIElement el = r.VisualHit as UIElement;
         if (el != null)
         {
             MouseButtonEventArgs e = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
             if (leftMouseDown) e.RoutedEvent = Mouse.MouseDownEvent;
             else e.RoutedEvent = Mouse.MouseUpEvent;
             el.RaiseEvent(e);
         }
         return HitTestResultBehavior.Continue;
     }), p);

您可以通过PostMessage将WM_MOUSEMOVE之类的windows消息发送到WPF窗口的HWND。。win32方法。我相信这些消息会被WPF读取并执行,就像来自用户一样。

如果你真的感到勇敢,你可以试试。从那里,您可以将交换链中的backbuffer复制到d3d场景中。如果您使用的是9Ex Vista D3D9,则可以利用共享资源在设备和进程之间共享曲面/纹理等功能来提高性能


您可能仍然需要对windows消息进行一些处理以实现交互性。

此方法的第一个问题是元素不应位于窗口上。但是,即使我创建了一个并将元素放在上面,消息也不会由WPF处理。我在窗口、用户控件、网格上使用了事件处理程序,最后在按钮和矩形等元素上使用了事件处理程序。不过,封装HwndSource的WPF窗口正在接收窗口消息。当我在HwndSource类中添加了我自己的消息钩子时,我可以看出这一点。消息应该像来自用户一样执行。但显然不是,我也不知道为什么。经过数小时的分解和逐步调试,我在HwndMouseInputProvider.ReportInput中找到了原因:WPF窗口未处于活动状态,GetCapture API函数不返回窗口的句柄。因此,非活动窗口确实会接收消息,但WPF互操作处理程序会丢弃这些消息。很容易修复,我想,但是简单地在WPF窗口上调用Activate或者用SetCapture设置句柄都没有帮助。我会挖得更深…好吧,我的错。我在发送消息后直接用SetCapture重置句柄,忘记了窗口消息系统不会立即发送消息。现在,它与我发送的第一条消息一起工作,但由于鼠标捕获句柄已设置为WPF窗口,因此无法识别诸如WM_LMOUSEDOWN之后的WM_LMOUSEUP之类的后续交互。