2010-10-08 7 views
19

Lo que realmente quiero es una versión de IsHitTestVisible que ignora ratón clic eventos, pero todavía las trampas de ratón entrar y salir eventos.WPF: Ignorar clics del ratón en superposición/adorner, pero manejar MouseEnter caso

Antecedentes: Una superposición informativa aparece bajo el control con el foco siempre. Este es un requisito, por lo que no tengo la libertad de eliminar este comportamiento. Esto se implementa utilizando un adorno que contiene una forma de rectángulo, lleno con un pincel de imagen. Todos los controles se crean programáticamente, sin XAML.

Comportamiento deseado: Cuando el usuario pasa el rectángulo, debe volverse 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 pasarse a cualquier control que esté debajo de la superposición, justo donde hizo clic el usuario.

Problema: si fijo IsHitTestVisible a True para permitir clics del ratón para pasar a través, no consigo eventos MouseEnter.

¿Existe una manera simple de dejar IsHitTestVisible True, y luego pasar todos menos 2-3 eventos al control correcto debajo del adorno? Estoy buscando una solución que no implique calcular qué control hay debajo del cursor, ya que WPF es claramente capaz de hacer esto por mí.

Como alternativa, ¿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 estar dejando IsHitTestVisible cierto, y el uso de la API de WPF hit pruebas para averiguar qué tipo de control fue la base del ratón cursor; si es uno que conozco, le enviaré un comando Click. Sin embargo, no estoy seguro si vale la pena hacerlo; a partir de ahora, al hacer clic, se desactiva mi superposición para que el usuario solo tenga que hacer clic dos veces.

Gracias!

+0

¿Alguna vez resolvió esto? Tengo exactamente el mismo requisito. – Grokys

Respuesta

7

Dado que IsHitTestVisible = "False" deshabilita todas las interacciones del mouse, no parece ser una forma clara de hacerlo. Probé

  • Configuración IsHitTestVisible = "false" en OnPreviewMouseDown y vuelva a hacer clic en el adorner usando UIAutomation pero no dados
  • Encuadernación la opacidad a un elemento "invisible" bajo el Adorner de manera que el clic pasaría a través . Pasó bien, pero por supuesto el problema era el mismo en el siguiente nivel así que no hay dados.

Parece que la única manera de conseguir realmente que esto funcione es establecer IsHitTestVisible = "false" en OnMouseDown y luego simular una nueva MouseClick usando SendInput. No es muy bonito, pero hace el trabajo bien.

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

Vamos estrictamente a WPF en este proyecto, no se permiten cosas heredadas. Pero gracias por la sugerencia. – stone

Cuestiones relacionadas