2010-10-08 91 views
19

我真正想要的是IsHitTestVisible的一個版本,忽略了鼠標點擊事件但仍捕獲鼠標進入和離開事件。WPF:忽略上疊加/裝飾器的鼠標點擊,但處理MouseEnter事件

背景: 每次在焦點控制下彈出信息覆蓋圖。這是一項要求,所以我無權刪除此行爲。這是使用包含矩形形狀的裝飾器來實現的,該矩形填充了圖像畫筆。所有控件都以編程方式創建,不涉及XAML。

期望的行爲: 當通過矩形用戶將鼠標,它應該成爲部分透明的。這樣他們就可以看到疊加層下面的其他控件並點擊它們。 當用戶點擊疊加層時,應該將點擊傳遞給覆蓋層下的任何控件,就在用戶點擊的位置。

問題: 如果我設置IsHitTestVisible爲True,讓鼠標點擊通過,我不明白的MouseEnter事件。

有一個簡單的方式離開IsHitTestVisible True,然後通過所有,但2-3事件裝飾器下方的正確的控制?我正在尋找一種解決方案,不涉及計算光標下的控件,因爲WPF顯然能夠爲我做這件事。

或者,我可以設置IsHitTestVisible爲False,但然後用另一種簡單的方法來確定,當鼠標移動到裝飾器?

更新:我仍在期待一個答案,但截至目前最有前途的解決方案似乎離開IsHitTestVisible真實的,並使用WPF命中測試的API搞清楚是鼠標底下是什麼類型的控制光標;如果這是我所知道的,我會發送一個Click命令給它。不知道這是否值得做,但;截至目前點擊解除我的覆蓋,所以用戶只需點擊兩次。

謝謝!

+0

你有沒有解決這個問題?我有完全相同的要求。 – Grokys 2014-02-06 19:38:59

回答

7

由於IsHitTestVisible =「False」會禁用所有的鼠標交互,所以似乎沒有任何干淨的方式來做到這一點。我試圖

  • 在OnPreviewMouseDown設置IsHitTestVisible =「假」,然後再單擊使用UIAutomation裝飾器,但沒有骰子
  • 綁定不透明度爲一個「看不見」的元素裝飾器下,這樣的點擊將通過。它通過了所有的權利,但當然問題在下一個層次上是一樣的,所以沒有骰子。

似乎只有這樣才能真正實現這個工作,就是在OnMouseDown中設置IsHitTestVisible =「False」,然後使用SendInput模擬一個新的MouseClick。不是很漂亮,但它完成了工作。

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

我們在這個項目中嚴格執行WPF,沒有允許任何遺留的東西。但謝謝你的建議。 – stone 2011-01-14 06:46:21