2010-10-08 13 views
19

Quello che voglio davvero è una versione di IsHitTestVisible che ignora del mouse click eventi, ma ancora trappole per topi entrare e uscire eventi.WPF: Ignora clic del mouse su di sovrapposizione/strumento decorativo, ma gestire MouseEnter evento

Sfondo: Un overlay informativo si apre sotto il controllo con focus ogni volta. Questo è un requisito, quindi non sono libero di rimuovere questo comportamento. Questo è implementato usando un decor contenente una forma rettangolare, riempita con un pennello immagine. Tutti i controlli sono creati in modo programmatico, nessun XAML coinvolto.

Comportamento desiderato: Quando l'utente esegue il mouse sopra il rettangolo, dovrebbe diventare parzialmente trasparente. Questo è così che possono vedere gli altri controlli sotto l'overlay e fare clic su di essi. Quando l'utente fa clic sull'overlay, il clic deve essere passato a qualsiasi controllo si trovi sotto l'overlay, proprio dove l'utente ha fatto clic.

Problema: se ho impostato IsHitTestVisible su True per consentire clic del mouse per passare attraverso, non ottengo eventi MouseEnter.

C'è un modo semplice per lasciare IsHitTestVisible True e quindi passare tutti tranne 2-3 eventi al controllo corretto sotto l'adorner? Sto cercando una soluzione che non implichi il calcolo di quale controllo si trova al di sotto del cursore, dal momento che WPF è chiaramente in grado di farlo per me.

In alternativa, è possibile impostare IsHitTestVisible su False ma utilizzare un altro metodo semplice per determinare quando il mouse si trova sopra l'adorner?

UPDATE: sto ancora sperando in una risposta, ma fin d'ora la soluzione più promettente sembra essere lasciando IsHitTestVisible vero, e utilizzando il WPF HIT testare le API per capire che tipo di controllo era sotto il mouse cursore; se fosse uno di quelli che conosco, manderei un comando Click. Non sono sicuro che valga la pena farlo, comunque; A partire da ora, fa clic su Ignora il mio overlay, quindi l'utente deve solo fare clic due volte.

Grazie!

+0

Hai mai risolto questo? Ho esattamente lo stesso requisito. – Grokys

risposta

7

Poiché IsHitTestVisible = "False" disabilita tutte le interazioni con il mouse, non sembra essere un modo pulito per farlo. Ho provato

  • Impostazione IsHitTestVisible = "False" in OnPreviewMouseDown e poi ri-clic sulla adorner utilizzando UIAutomation ma niente da fare
  • Binding l'opacità di un elemento "invisibile" sotto l'Adorner in modo che il clic attraverserebbe . È passato bene, ma ovviamente il problema era lo stesso al livello successivo, quindi niente da fare.

Sembra che l'unico modo per farlo funzionare sia impostare IsHitTestVisible = "False" in OnMouseDown e quindi simulare un nuovo MouseClick utilizzando SendInput. Non molto carina ma ha fatto il lavoro.

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

Stiamo andando rigorosamente in WPF in questo progetto, nessuna roba legacy consentita. Ma grazie per il suggerimento. – stone