本文介绍了WPF:忽略鼠标单击叠加/装饰,但处理MouseEnter事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真正想要的是IsHitTestVisible的版本,该版本会忽略鼠标 click 事件,但仍会捕获鼠标进入和离开事件.

What I really want is a version of IsHitTestVisible that ignores mouse click events but still traps mouse enter and leave events.

背景:每当有焦点时,信息叠加层就会在控件的控制下弹出.这是一项要求,因此我无权删除此行为.这是通过使用包含矩形笔刷的装饰器来实现的,该矩形器填充有图像笔刷.所有控件均以编程方式创建,不涉及XAML.

Background:An informational overlay pops up under the control with focus whenever. This is a requirement, so I'm not at liberty to remove this behavior. This is implemented using an adorner containing a Rectangle shape, filled with an image brush. All controls are created programatically, no XAML involved.

所需行为:当用户将鼠标悬停在Rectangle上时,它应该变得部分透明.这样一来,他们可以看到叠加层下方的其他控件,然后单击它们.当用户点击叠加层时,点击应该传递到叠加层下方的任何控件上,即用户点击的位置.

Desired behavior:When user mouses over the Rectangle, it should become partially transparent. This is so that they can see the other controls beneath the overlay and click them.When the user clicks on the overlay, the click should be passed through to whatever control is under the overlay, right where the user clicked.

问题:如果我将 IsHitTestVisible 设置为True以允许通过鼠标单击,则不会获得MouseEnter事件.

Problem:If I set IsHitTestVisible to True to allow mouse clicks to pass through, I don't get MouseEnter events.

是否有一种简单的方法可以将IsHitTestVisible设置为True,然后将除2-3个事件以外的所有事件传递给装饰器下的正确控件?我正在寻找一种不涉及计算光标下方控件的解决方案,因为WPF显然能够为我做到这一点.

Is there a simple way to leave IsHitTestVisible True, and then pass all but 2-3 events to the correct control beneath the adorner? I'm looking for a solution that does not involve calculating what control is beneath the cursor, since WPF is clearly capable of doing this for me.

或者,我可以将IsHitTestVisible设置为False,然后使用另一种简单的方法来确定鼠标何时位于装饰物上吗?

Alternatively, could I set IsHitTestVisible to False but then use another simple method to determine when the mouse is over the adorner?

更新:我仍然希望得到一个答案,但是到目前为止,最有希望的解决方案似乎是将IsHitTestVisible保留为t​​rue,并使用WPF命中测试API找出哪种控件类型在鼠标光标的下面;如果是我所知道的,我会向它发送一个Click命令.不过,不确定是否值得这样做;截至目前,单击将关闭我的叠加层,因此用户只需单击两次即可.

UPDATE: I'm still hoping for an answer, but as of now the most promising solution seems to be leaving IsHitTestVisible true, and using the WPF hit testing APIs to figure out what type of control was underneath the mouse cursor; if it was one I know about, I'd send a Click command to it. Not sure if this is worth doing, though; as of now clicking dismisses my overlay so the user just has to click twice.

谢谢!

推荐答案

由于IsHitTestVisible ="False"禁用了所有鼠标交互,因此似乎并不是一种干净的方法.我尝试过

Since IsHitTestVisible="False" disables all mouse interaction, it doesn't seem to be any clean way of doing this. I tried

  • 在OnPreviewMouseDown中设置IsHitTestVisible ="False",然后使用UIAutomation但没有骰子重新单击装饰器
  • 将不透明度绑定到Adorner下的不可见"元素,以使点击通过.它顺利通过了,但是当然问题在下一个级别上是相同的,因此没有骰子.

似乎唯一可行的方法是在OnMouseDown中设置IsHitTestVisible ="False",然后使用SendInput模拟新的MouseClick.不是很漂亮,但是可以完成工作.

Seems like the only way to actually get this to work is to set IsHitTestVisible="False" in OnMouseDown and then simulate a new MouseClick using SendInput. Not very pretty but it gets the job done.

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

这篇关于WPF:忽略鼠标单击叠加/装饰,但处理MouseEnter事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 14:00