WPF中的ContextMenuOpening事件为什么不触发?

17

我有一个资源字典,其中包含一个上下文菜单:

<ResourceDictionary x:Class="MyApp.Components.MyContextMenu"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:MyApp"
                    xmlns:components="clr-namespace:MyApp.Components">
    <ContextMenu ContextMenuOpening="OnContextMenuOpening">

资源字典的 XAML 具有以下代码:

using System;
using System.Windows;
using System.Windows.Controls;

namespace MyApp.Components
{
    public partial class MyContextMenu : ResourceDictionary
    {
        public MyContextMenu()
        {
            InitializeComponent();
        }  

        void OnContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            Console.WriteLine("here i am!");
        }
    }
}
日志没有显示。我想知道为什么事件没有触发或者没有到达正确的位置 - 问题是因为我将上下文菜单包装在这个资源字典中吗?
更新:有趣的是,如果我删除代码后面的函数,编译时会出现错误:
“ContextMenu_OnContextMenuOpening”不包含对“MyApp.Components.MyContextMenu”类型的第一个参数的定义,也找不到接受该类型作为第一个参数的扩展方法“ContextMenu_OnContextMenuOpening”(是否缺少使用指令或程序集引用?)
更新2:看起来 Console.WriteLine Debug.WriteLine 都能产生输出,但只有在我点击项目底部附近时才会“随机”地产生输出。可能是某种碰撞检测出了问题?

你想在WPF应用程序中查看Console.WriteLine的输出结果吗? 将其更改为System.Diagnostics.Debug.WriteLine,然后在输出窗口中检查。 - nemesv
@nemesv 已尝试。请查看我的更新问题。 - Tower
5个回答

54

ContextMenuOpening事件必须在ContextMenu的祖先上处理,而不是在ContextMenu本身上处理。如果您尝试在ContextMenu上处理它,则事件仅在右键单击打开ContextMenu后才触发。


7
好的,现在你正在尝试捕捉上下文菜单的打开方式。 - Daria

9
我相信kurrazyman的答案是正确的,但我花了一些时间才理解它。 在我的情况下,我有一个带有上下文菜单的TreeView控件。 使用myTreeView.ContextMenu.ContextMenuOpening无效,但使用myTreeView.ContextMenuOpening有效。

8

这不是一个bug,它正常工作…这里最常见的错误是大多数人在ContextMenuOpening事件中犯的错误…考虑以下两种不同的情况,以找出这个问题的真正原因:

情况1(不起作用):

<ListBox Name="lb_sizes" Height="120">
<ListBox.ContextMenu>
<ContextMenu ContextMenuOpening="My_ContextMenuOpening">
<MenuItem Header="Delete"/>
<MenuItem Header="Delete All"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>

场景2(此方案可行):

<ListBox Name="lb_sizes" Height="120" ContextMenuOpening="My_ContextMenuOpening">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete"/>
<MenuItem Header="Delete All"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>

唯一的区别在于将ContextMenuOpening事件分配给适当的元素... 在场景1中,它被分配(附加)到<ContextMenu>元素上,在场景2中,它被分配到<ListBox>元素上,这是正确的方法,应该可以工作。

哦,我在那个问题上被抓住了!你是对的。我在ContextMenu本身上使用了ContextMenuOpening,这是错误的。在我的情况下,它应该在ListView上。这显然也适用于代码后台(您可以使用“Handles ListView.ContextMenuOpening”处理事件)。非常感谢。 - gouderadrian

7

8
这不应该被标记为答案。因为这并不是框架中的一个错误,而是按设计工作的。 kurrazyman 的回答是正确的。 - Skrymsli
1
抱歉,hsCode和RichTurner的回答是正确的。ContextMenuOpening应该从ListView而不是ContextMenu本身进行处理。 - gouderadrian

1
我正在使用 IsVisibleChanged 事件:
private void ContextMenu_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    var isVisible = (bool)e.NewValue;
    if (isVisible)
    {
        //...
    }
}

我无法像真正的答案中提到的那样使用父级,因为我的上下文菜单驻留在Nuget的TaskbarIcon控件中;而且似乎该控件会吞噬其他消息。 - ΩmegaMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接