隧道事件和上下文菜单

发布于 2024-10-08 04:19:01 字数 913 浏览 0 评论 0原文

我有以下 WPF 控件,其行为应该像 GoogleMaps 那样(左双击缩放,右双击取消缩放):

<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 时,UnZoom 方法不起作用,因为 ScrollViewer 上不再捕获 DoubleClick 事件...

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

I have the following WPF Control, that should behave like, by e.g. GoogleMaps does(zoom on left double click, unzoom on right double click):

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

And some code:

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;
    }
}

The problem is that When myCanvas have a ContextMenu the UnZoom method does not work, because DoubleClick event is not catched anymore on ScrollViewer...

Setting this.myCanvas.ContextMenu = null; solves the problem, but Is there a way to bypass this?...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浮生面具三千个 2024-10-15 04:19:01

更新
上传了演示效果的小示例项目。
http://www.mediafire.com/?du2jr18khx8ooy9

我为此尝试了很多不同的方法我发现的最接近的事情是将 ContextMenu 的 Horizo​​ntalOffset 偏移 1。这允许在上下文菜单打开时右键双击。当 ContextMenu 未打开时它仍然不起作用,因为 ScrollViewer 仅收到第一次单击。

您可以通过使用第一次鼠标右键单击的计时代码来解决此问题,如果在线程耗尽之前再次单击鼠标右键,则可以使用 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()));
    }
}

Update
Uploaded small sample project demonstrating the effect.
http://www.mediafire.com/?du2jr18khx8ooy9

I tried a bunch of different approaches for this and the closest thing I found was to offset the HorizontalOffset by 1 for the ContextMenu. This allowed for right-double-click when the ContextMenu was open. It still didn't work when the ContextMenu wasn't open since the ScrollViewer only recieved the first click.

You could work around this by using your timing code for the first right-mouse-click and if another right-mouse-click occurs before the Thread runs out, you simulate another right-mouse-click using SendInput. Although it may not be so pretty, I gets the job done.

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

Code behind

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()));
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文