WPF:忽略鼠标点击overlay / adorner,但处理MouseEnter事件

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (23)

我真正想要的是IsHitTestVisible的一个版本,它忽略鼠标点击事件,但仍捕捉鼠标进入和离开事件。

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

期望的行为:当用户将鼠标悬停在矩形上时,它应该变得部分透明。这样他们就可以看到叠加层下面的其他控件并点击它们。当用户点击叠加层时,点击应该通过覆盖层下的任何控制,就在用户点击的地方。

问题:如果我将IsHitTestVisible设置为True以允许鼠标点击通过,我不会收到MouseEnter事件。

有没有简单的方法让IsHitTestVisible成为True,然后将2-3个事件都传递给装饰者下面的正确控件?我正在寻找一种解决方案,不涉及计算光标下的控件,因为WPF显然能够为我做这件事。

或者,我可以将IsHitTestVisible设置为False,但是接下来使用另一种简单的方法来确定鼠标何时位于装饰器上?

我仍然希望得到一个答案,但截至目前为止,最有希望的解决方案似乎是让IsHitTestVisible成为true,并使用WPF命中测试API来确定鼠标光标下方的控件类型; 如果这是我所知道的,我会发送一个Click命令给它。不知道这是否值得做,但; 截至目前点击解除我的覆盖,所以用户只需点击两次。

提问于
用户回答回答于

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

  • 在OnPreviewMouseDown中设置IsHitTestVisible =“False”,然后使用UIAutomation重新点击装饰者,但没有骰子
  • 将不透明度绑定到Adorner下的“不可见”元素,以便点击可以通过。它通过了所有的权利,但当然问题在下一个层次上是一样的,所以没有骰子。

似乎真正实现这一点的唯一方法是在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()));
    }
}

扫码关注云+社区

领取腾讯云代金券