调用上下文菜单打开

发布于 2024-10-08 04:46:06 字数 3518 浏览 5 评论 0原文

我需要做一些像 Google 地图那样的事情(但在 WPF 中):

  • 当在地图上 RightClick 时,我有一个 ContextMenu。
  • RightDoubleClicking 时,我有 UnZoom 操作。

所以,显然,这在 WPF 中有点困难...... 经过一番努力和搜索后,读到有人抱怨“我们无法预测未来”(我问自己 Google 如何预测未来),我决定“等待”SystemInformation.DoubleClickTime 并且只然后显示上下文菜单。

当然,这并不理想,甚至是人类可观察到的,但我不知道其他方法。

所以,我对以下代码的问题是(我有一个自定义画布):

ContextMenuEventArgs lastContextMenuEventArgs = null;
bool? lastContextMenuEventArgsHandled = null;

protected override void OnContextMenuOpening(ContextMenuEventArgs e)
{
    lastContextMenuEventArgs = e;
    lastContextMenuEventArgsHandled = e.Handled;

    e.Handled = true;
    //base.OnContextMenuOpening(e);
}

bool rightMouseClickedOnce = false;
protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e)
{
    //base.OnPreviewMouseRightButtonUp(e);

    Console.WriteLine(">>>>>>>>>>> OnPreviewMouseRightButtonUp");
    if (!rightMouseClickedOnce)
    {
        rightMouseClickedOnce = 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()
                            {
                                if (rightMouseClickedOnce)
                                {
                                    Console.WriteLine(">>>>>>>>>>> Right Click");
                                    rightMouseClickedOnce = false;
                                    base.OnPreviewMouseRightButtonUp(e);

                                    if (lastContextMenuEventArgsHandled.HasValue)
                                    {
                                        Console.WriteLine(">>>>>>>>>>> lastContextMenuEventArgsHandled");
                                        lastContextMenuEventArgs.Handled = lastContextMenuEventArgsHandled.Value;
                                        base.OnContextMenuOpening(lastContextMenuEventArgs);
                                        lastContextMenuEventArgsHandled = null;
                                    }
                                    //if (this.ContextMenu != null)
                                    //{
                                    //  this.ContextMenu.PlacementTarget = this;
                                    //  this.ContextMenu.IsOpen = true;
                                    //}
                                }
                            }
                    ));
                }
        ));
        thread.Start();
    }
    else if (rightMouseClickedOnce)
    {
        Console.WriteLine(">>>>>>>>>>> Right Double Click");
        rightMouseClickedOnce = false;
        base.OnPreviewMouseRightButtonUp(e);
        this.OnMouseRightDoubleClick(e);
    }

}

一切都很好,但有一点问题:base.OnContextMenuOpening(lastContextMenuEventArgs);似乎不起作用...

我之前设置过

if (this.ContextMenu != null)
{
  this.ContextMenu.PlacementTarget = this;
  this.ContextMenu.IsOpen = true;
}

并且有效,但最终这会阻止子 contextMenu 元素打开,并始终打开父(画布)contextMenu。

我可以只调用 contextMenu 事件吗?

I need to do something like Google Maps does (but in WPF):

  • when RightClick on the map I have a ContextMenu.
  • when RightDoubleClicking I have the UnZoom action.

So, apparently, this is a little difficult in WPF...
After struggling and searching a lot, read people that compains that "we can't predict the future" (I ask myself how does Google predict it), I decided to "wait" SystemInformation.DoubleClickTime and only then display a contextMenu.

Surely, this is not ideal, even human-observable, but I don't know other method.

So, the problem that I have with the following code is (I have a custom Canvas):

ContextMenuEventArgs lastContextMenuEventArgs = null;
bool? lastContextMenuEventArgsHandled = null;

protected override void OnContextMenuOpening(ContextMenuEventArgs e)
{
    lastContextMenuEventArgs = e;
    lastContextMenuEventArgsHandled = e.Handled;

    e.Handled = true;
    //base.OnContextMenuOpening(e);
}

bool rightMouseClickedOnce = false;
protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e)
{
    //base.OnPreviewMouseRightButtonUp(e);

    Console.WriteLine(">>>>>>>>>>> OnPreviewMouseRightButtonUp");
    if (!rightMouseClickedOnce)
    {
        rightMouseClickedOnce = 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()
                            {
                                if (rightMouseClickedOnce)
                                {
                                    Console.WriteLine(">>>>>>>>>>> Right Click");
                                    rightMouseClickedOnce = false;
                                    base.OnPreviewMouseRightButtonUp(e);

                                    if (lastContextMenuEventArgsHandled.HasValue)
                                    {
                                        Console.WriteLine(">>>>>>>>>>> lastContextMenuEventArgsHandled");
                                        lastContextMenuEventArgs.Handled = lastContextMenuEventArgsHandled.Value;
                                        base.OnContextMenuOpening(lastContextMenuEventArgs);
                                        lastContextMenuEventArgsHandled = null;
                                    }
                                    //if (this.ContextMenu != null)
                                    //{
                                    //  this.ContextMenu.PlacementTarget = this;
                                    //  this.ContextMenu.IsOpen = true;
                                    //}
                                }
                            }
                    ));
                }
        ));
        thread.Start();
    }
    else if (rightMouseClickedOnce)
    {
        Console.WriteLine(">>>>>>>>>>> Right Double Click");
        rightMouseClickedOnce = false;
        base.OnPreviewMouseRightButtonUp(e);
        this.OnMouseRightDoubleClick(e);
    }

}

Everything works great but a little problem: base.OnContextMenuOpening(lastContextMenuEventArgs); does not seem to work...

I set before

if (this.ContextMenu != null)
{
  this.ContextMenu.PlacementTarget = this;
  this.ContextMenu.IsOpen = true;
}

and that worked, but finally this blocks child contextMenu elements from opening, and open always the parent (canvas) contextMenu.

Can I just invoke the contextMenu event?

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

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

发布评论

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

评论(1

深居我梦 2024-10-15 04:46:06

我对 WPF 不太了解,但是您能否显示菜单,例如距光标一个像素,并查看用户是否在同一位置以及在系统双击时间内再次右键单击?我曾经在游戏中使用过类似的技术,而且效果很好。
菜单“淡入”(也可以选择淡出)动画可以让它变得更好。

I don't know much about WPF, but can you show the menu, say, a pixel away from the cursor and see if the user right-clicks again in the same spot and in the system double click time? I've used a similar technique once in a game and it performed nice enough.
A menu "fade in" (optionally, out, too) animation could make it even better.

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