wpf mouseevent adorner transparent-control

WPF: ignore los clics del mouse en la superposición/adornador, pero maneje el evento MouseEnter



mouseevent adorner (1)

Lo que realmente quiero es una versión de IsHitTestVisible que ignore los eventos de clic del mouse, pero aún así atrapa los eventos de entrar y salir del mouse.

Antecedentes: una superposición informativa aparece bajo el control con enfoque siempre. Este es un requisito, por lo que no estoy en libertad de eliminar este comportamiento. Esto se implementa utilizando un adorno que contiene una forma de rectángulo, rellena con un pincel de imagen. Todos los controles se crean mediante programación, sin XAML involucrado.

Comportamiento deseado: cuando el usuario pasa por encima del Rectángulo, debe ser parcialmente transparente. Esto es para que puedan ver los otros controles debajo de la superposición y hacer clic en ellos. Cuando el usuario hace clic en la superposición, el clic debe pasar a cualquier control que se encuentre debajo de la superposición, justo donde el usuario hizo clic.

Problema: si configuro IsHitTestVisible en True para permitir que pasen los clics del ratón, no obtengo eventos MouseEnter.

¿Hay una forma sencilla de dejar IsHitTestVisible True y luego pasar todos los eventos, excepto 2-3, al control correcto debajo del adorno? Estoy buscando una solución que no implique calcular qué control está debajo del cursor, ya que WPF es claramente capaz de hacerlo por mí.

Alternativamente, ¿podría establecer IsHitTestVisible en False pero luego usar otro método simple para determinar cuándo el mouse está sobre el adorno?

ACTUALIZACIÓN : todavía estoy esperando una respuesta, pero a partir de ahora la solución más prometedora parece ser dejar IsHitTestVisible verdadero, y usar las API de prueba de aciertos de WPF para averiguar qué tipo de control estaba debajo del cursor del mouse; si fuera uno que yo conozca, le enviaría un comando de clic. Sin embargo, no estoy seguro de si vale la pena hacerlo; a partir de ahora, hacer clic descarta mi superposición por lo que el usuario solo tiene que hacer clic dos veces.

¡Gracias!


Ya que IsHitTestVisible = "False" desactiva todas las interacciones del mouse, no parece ser una forma clara de hacerlo. Lo intenté

  • Configurando IsHitTestVisible = "False" en OnPreviewMouseDown y luego volviendo a hacer clic en el adornador usando UIAutomation pero sin dados
  • Vincular la opacidad a un elemento "invisible" debajo del Adornador para que el clic pase. Pasó bien, pero por supuesto, el problema era el mismo en el siguiente nivel, por lo que no hay dados.

Parece que la única manera de hacer que esto funcione es establecer IsHitTestVisible = "False" en OnMouseDown y luego simular un nuevo MouseClick usando SendInput. No es muy bonito pero hace el trabajo.

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