2010-10-08 11 views
19

Co naprawdę chcę to wersja IsHitTestVisible że ignoruje mysz kliknij wydarzeń, ale nadal pułapek na myszy wjazdu i opuszczenia wydarzenia.WPF: ignorowanie kliknięć myszy na nakładki/adorner, ale obsługiwać MouseEnter zdarzenie

Tło: Nakładka informacyjna pojawia się pod kontrolą z fokusem zawsze. Jest to wymaganie, więc nie mam prawa usunąć tego zachowania. Jest to realizowane za pomocą adornera zawierającego kształt Rectangle, wypełniony pędzlem obrazu. Wszystkie kontrole są tworzone programowo, bez udziału XAML.

Żądane zachowanie: Gdy użytkownik myszy myszy nad prostokącie, powinien stać się częściowo przezroczysty. Jest tak, że widzą inne kontrolki pod nakładką i je klikają. Gdy użytkownik kliknie nakładkę, kliknięcie należy przekazać do dowolnej kontrolki znajdującej się pod nakładką, dokładnie tam, gdzie użytkownik kliknął.

Problem: Jeżeli ustawić IsHitTestVisible True aby umożliwić kliknięć myszą, aby przejść, nie dostać wydarzenia MouseEnter.

Czy istnieje prosty sposób, aby opuścić IsHitTestVisible True, a następnie przekazać wszystkie zdarzenia oprócz 2-3, aby uzyskać prawidłową kontrolę pod adornerem? Szukam rozwiązania, które nie wymaga obliczenia, jaka kontrola znajduje się poniżej kursora, ponieważ WPF jest w stanie zrobić to za mnie.

Czy można ustawić wartość IsHitTestVisible na False, a następnie użyć innej prostej metody, aby określić, kiedy mysz znajduje się nad adornerem?

UPDATE: Mam jeszcze nadzieję na odpowiedź, ale jak na razie najbardziej obiecującym rozwiązaniem wydaje się być pozostawiając IsHitTestVisible prawdą, a przy użyciu WPF hit testowania API, aby dowiedzieć się, jaki rodzaj kontroli był pod mysz kursor; jeśli to był taki, o którym wiem, wysłałbym do niego polecenie Click. Nie jestem pewien, czy warto to robić; od teraz kliknięcie odrzuca moją nakładkę, więc użytkownik musi kliknąć dwa razy.

Dzięki!

+0

Czy kiedykolwiek rozwiązałeś to? Mam dokładnie to samo wymaganie. – Grokys

Odpowiedz

7

Ponieważ IsHitTestVisible = "False" wyłącza wszystkie interakcje myszy, nie wydaje się, żeby to był czysty sposób. Próbowałem

  • Ustawianie IsHitTestVisible = „false” w OnPreviewMouseDown a następnie ponowne kliknięcie adorner użyciu UIAutomation ale nie ma kości
  • Oprawa krycie do „niewidzialnego” element pod Adorner tak, że kliknięcie będzie przechodzić przez . Minęło dobrze, ale oczywiście problem był taki sam na następnym poziomie, więc nie ma kości.

Wydaje się, że jedynym sposobem, aby to zrobić, jest ustawienie IsHitTestVisible = "False" w OnMouseDown, a następnie symulacja nowego MouseClick za pomocą SendInput. Niezbyt ładna, ale wykonuje swoją robotę.

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

Przechodzimy ściśle do WPF w tym projekcie, bez żadnych starych rzeczy. Ale dzięki za sugestię. – stone

Powiązane problemy