2010-12-16 64 views
1

我有以下的WPF控件,应该表现得像谷歌地图没有(放大左双击,放大还原右键双击):隧道事件和ContextMenu

<Grid> 
    <ScrollViewer x:Name="scrollViewer"> 
     <Canvas x:Name="myCanvas"/> 
    </ScrollViewer> 
</Grid> 

而且一些代码:

void OnScrollViewerPreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) 
{ 
    //this.myCanvas.ContextMenu = null; 
    if (e.OriginalSource is Canvas) 
    { 
     // zoom on left doubleClick 
     if (e.ChangedButton == MouseButton.Left) 
     { 
      ZoomOnMouseOnce(); 
     } // UNzoom on right doubleClick 
     else if (e.ChangedButton == MouseButton.Right) 
     { 
      UnzoomOnMouseOnce(); 
     } 
     e.Handled = true; 
    } 
} 

的问题是,当myCanvas有一个ContextMenu的放大还原方法不起作用,因为DoubleClick事件上没有的ScrollViewer逮住了......

设置this.myCanvas.ContextMenu = null;解决了这个问题,但是否有办法绕过这个?...

+0

你为什么不忽略上下文菜单,使用弹出打造你想要的确切功能? – 2010-12-16 20:57:36

+0

@Aaron:这没什么变化。问题依旧,上下文菜单或弹出... – serhio 2010-12-20 10:25:29

回答

1

更新
上传的小样本项目展示效果。
http://www.mediafire.com/?du2jr18khx8ooy9

我想这一堆不同的方法,我发现这是由1对文本菜单来抵消Horizo​​ntalOffset最接近。这可以在ContextMenu打开时进行右键双击。由于ScrollViewer只收到第一次点击,所以当ContextMenu未打开时它仍然不起作用。

您可以通过使用您的计时代码进行第一次右键单击来解决此问题,并且如果在线程用完之前发生另一次右键单击,则可以使用SendInput模拟另一个鼠标右键单击。虽然可能不那么漂亮,但我可以完成这项工作。

<Canvas ...> 
    <Canvas.ContextMenu> 
     <ContextMenu Placement="RelativePoint" HorizontalOffset="1"> 
      <MenuItem Header="MenuItem 1"/> 
     </ContextMenu> 
    </Canvas.ContextMenu> 

代码背后

private bool m_waitingForRightMouseDoubleClick = false; 
private void scrollViewer_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) 
{ 
    if (e.ChangedButton == MouseButton.Right) 
    { 
     if (m_waitingForRightMouseDoubleClick == false) 
     { 
      m_waitingForRightMouseDoubleClick = true; 
      Thread thread = new Thread(new System.Threading.ThreadStart(delegate() 
       { 
        Thread.Sleep(System.Windows.Forms.SystemInformation.DoubleClickTime); 
        this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, 
         new Action(delegate() 
          { 
           m_waitingForRightMouseDoubleClick = false; 
          } 
          )); 
       })); 
      thread.Start(); 
     } 
     else 
     { 
      MouseSimulator.ClickRightMouseButton(); 
     } 
    } 
} 

MouseSimulator.cs

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 ClickRightMouseButton() 
    { 
     INPUT mouseDownInput = new INPUT(); 
     mouseDownInput.type = SendInputEventType.InputMouse; 
     mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN; 
     SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT())); 

     INPUT mouseUpInput = new INPUT(); 
     mouseUpInput.type = SendInputEventType.InputMouse; 
     mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP; 
     SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT())); 
    } 
} 
+0

有趣。直到现在,最后我用了下面的代码:http://stackoverflow.com/questions/4492996/invoke-a-contextmenu-to-open – serhio 2010-12-20 20:22:31

+0

啊,我明白了,你也“等”了......方法的“不方便”我们都使用的是点击和菜单打开之间的可感知延迟。 – serhio 2010-12-20 20:26:19

+0

@serhio:使用此方法,即时打开ContextMenu。并从那里等待另一次点击,如果发生这种情况,它实际上会发送两次点击。因此,让我们右键双击 – 2010-12-20 20:29:38