WPF: игнорировать щелчки мышью на оверлее / оформителе, но обрабатывать событие MouseEnter - PullRequest
20 голосов
/ 08 октября 2010

Что мне действительно нужно, так это версия IsHitTestVisible, которая игнорирует события мыши click , но все еще удерживает мышь , вводит и оставляет события.

Фон: всплывающее информационное наложениепод контролем с фокусом всякий раз.Это требование, поэтому я не могу удалить это поведение.Это реализовано с помощью украшения, содержащего форму прямоугольника, заполненного кистью изображения.Все элементы управления создаются программно, без участия XAML.

Желаемое поведение: когда пользователь наводит курсор на прямоугольник, он должен стать частично прозрачным.Это сделано для того, чтобы они могли видеть другие элементы управления под наложением и щелкать по ним.Когда пользователь нажимает на оверлей, щелчок должен передаваться любому элементу управления под оверлеем, там, где пользователь щелкнул.

Проблема: если для IsHitTestVisible установить значение True, чтобы позволить щелчкам мыши проходить, я не получаю события MouseEnter.

Есть ли простой способ оставить IsHitTestVisibleВерно, а затем передать все, кроме 2-3 событий на правильный контроль под обожателем?Я ищу решение, которое не включает вычисление того, какой элемент управления находится под курсором, поскольку WPF явно способен сделать это для меня.

В качестве альтернативы, можно ли установить IsHitTestVisible в False, но затем использовать другой простой методопределить, когда мышь находится над украшателем?

ОБНОВЛЕНИЕ : Я все еще надеюсь на ответ, но на данный момент наиболее многообещающим решением кажется оставить IsHitTestVisible true и использовать API-интерфейсы тестирования совпадений WPF, чтобы выяснить, какой типконтроль был под курсором мыши;если бы это был тот, о котором я знаю, я бы отправил ему команду Click.Не уверен, стоит ли это делать, хотя;на данный момент нажатие отменяет мой оверлей, поэтому пользователь просто должен щелкнуть дважды.

Спасибо!

1 Ответ

7 голосов
/ 16 декабря 2010

Поскольку IsHitTestVisible = "False" отключает все взаимодействия с мышью, похоже, это не совсем чистый способ сделать это. Я пытался

  • Установка IsHitTestVisible = "False" в OnPreviewMouseDown, а затем повторный щелчок по рекламодателю с помощью UIAutomation, но без игры в кости
  • Связывание непрозрачности с «невидимым» элементом под Adorner, чтобы щелчок проходил. Все прошло хорошо, но, конечно, проблема была такой же на следующем уровне, так что никаких кубиков.

Похоже, что единственный способ заставить это работать - установить IsHitTestVisible = "False" в OnMouseDown, а затем смоделировать новый MouseClick с помощью SendInput. Не очень красиво, но это делает работу.

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