2010-10-08 149 views
19

我真正想要的是IsHitTestVisible的一个版本,忽略了鼠标点击事件但仍捕获鼠标进入和离开事件。WPF:忽略上叠加/装饰器的鼠标点击,但处理MouseEnter事件

背景: 每次在焦点控制下弹出信息覆盖图。这是一项要求,所以我无权删除此行为。这是使用包含矩形形状的装饰器来实现的,该矩形填充了图像画笔。所有控件都以编程方式创建,不涉及XAML。

期望的行为: 当通过矩形用户将鼠标,它应该成为部分透明的。这样他们就可以看到叠加层下面的其他控件并点击它们。 当用户点击叠加层时,应该将点击传递给覆盖层下的任何控件,就在用户点击的位置。

问题: 如果我设置IsHitTestVisible为True,让鼠标点击通过,我不明白的MouseEnter事件。

有一个简单的方式离开IsHitTestVisible True,然后通过所有,但2-3事件装饰器下方的正确的控制?我正在寻找一种解决方案,不涉及计算光标下的控件,因为WPF显然能够为我做这件事。

或者,我可以设置IsHitTestVisible为False,但然后用另一种简单的方法来确定,当鼠标移动到装饰器?

更新:我仍在期待一个答案,但截至目前最有前途的解决方案似乎离开IsHitTestVisible真实的,并使用WPF命中测试的API搞清楚是鼠标底下是什么类型的控制光标;如果这是我所知道的,我会发送一个Click命令给它。不知道这是否值得做,但;截至目前点击解除我的覆盖,所以用户只需点击两次。

谢谢!

+0

你有没有解决这个问题?我有完全相同的要求。 – Grokys 2014-02-06 19:38:59

回答

7

由于IsHitTestVisible =“False”会禁用所有的鼠标交互,所以似乎没有任何干净的方式来做到这一点。我试图

  • 在OnPreviewMouseDown设置IsHitTestVisible =“假”,然后再单击使用UIAutomation装饰器,但没有骰子
  • 绑定不透明度为一个“看不见”的元素装饰器下,这样的点击将通过。它通过了所有的权利,但当然问题在下一个层次上是一样的,所以没有骰子。

似乎只有这样才能真正实现这个工作,就是在OnMouseDown中设置IsHitTestVisible =“False”,然后使用SendInput模拟一个新的MouseClick。不是很漂亮,但它完成了工作。

protected override void OnMouseDown(MouseButtonEventArgs e) 
{ 
    IsHitTestVisible = false; 

    Action action =() => 
    { 
     MouseSimulator.ClickLeftMouseButton(); 
     IsHitTestVisible = true; 
    }; 
    this.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle); 
} 

public class MouseSimulator 
{ 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); 

    [StructLayout(LayoutKind.Sequential)] 
    struct INPUT 
    { 
     public SendInputEventType type; 
     public MouseKeybdhardwareInputUnion mkhi; 
    } 
    [StructLayout(LayoutKind.Explicit)] 
    struct MouseKeybdhardwareInputUnion 
    { 
     [FieldOffset(0)] 
     public MouseInputData mi; 

     [FieldOffset(0)] 
     public KEYBDINPUT ki; 

     [FieldOffset(0)] 
     public HARDWAREINPUT hi; 
    } 
    [StructLayout(LayoutKind.Sequential)] 
    struct KEYBDINPUT 
    { 
     public ushort wVk; 
     public ushort wScan; 
     public uint dwFlags; 
     public uint time; 
     public IntPtr dwExtraInfo; 
    } 
    [StructLayout(LayoutKind.Sequential)] 
    struct HARDWAREINPUT 
    { 
     public int uMsg; 
     public short wParamL; 
     public short wParamH; 
    } 
    struct MouseInputData 
    { 
     public int dx; 
     public int dy; 
     public uint mouseData; 
     public MouseEventFlags dwFlags; 
     public uint time; 
     public IntPtr dwExtraInfo; 
    } 
    [Flags] 
    enum MouseEventFlags : uint 
    { 
     MOUSEEVENTF_MOVE = 0x0001, 
     MOUSEEVENTF_LEFTDOWN = 0x0002, 
     MOUSEEVENTF_LEFTUP = 0x0004, 
     MOUSEEVENTF_RIGHTDOWN = 0x0008, 
     MOUSEEVENTF_RIGHTUP = 0x0010, 
     MOUSEEVENTF_MIDDLEDOWN = 0x0020, 
     MOUSEEVENTF_MIDDLEUP = 0x0040, 
     MOUSEEVENTF_XDOWN = 0x0080, 
     MOUSEEVENTF_XUP = 0x0100, 
     MOUSEEVENTF_WHEEL = 0x0800, 
     MOUSEEVENTF_VIRTUALDESK = 0x4000, 
     MOUSEEVENTF_ABSOLUTE = 0x8000 
    } 
    enum SendInputEventType : int 
    { 
     InputMouse, 
     InputKeyboard, 
     InputHardware 
    } 

    public static void ClickLeftMouseButton() 
    { 
     INPUT mouseDownInput = new INPUT(); 
     mouseDownInput.type = SendInputEventType.InputMouse; 
     mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN; 
     SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT())); 

     INPUT mouseUpInput = new INPUT(); 
     mouseUpInput.type = SendInputEventType.InputMouse; 
     mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP; 
     SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT())); 
    } 
} 
+0

我们在这个项目中严格执行WPF,没有允许任何遗留的东西。但谢谢你的建议。 – stone 2011-01-14 06:46:21