WPF 上下文菜单 Click 事件在一个地方有效,在另一个地方无效

WPF Context Menu Click event works in one place, not in another

我有以下 XAML 生成一个列表框,其中每个项目都在扩展器中包含另一个列表框,并且我已将 PageContextMenu 定义为顶级列表的上下文菜单,并且 FrameContextMenu 用于较低级别的列表。

问题:两者都显示正确,但点击事件只在顶层上下文菜单上起作用,而不在下层上下文菜单上起作用。例如,单击 PageContextMenu 中的 Delete Selected 会正确调用关联的处理程序,但单击 FrameContextMenu 中的 Delete Selected Frame(s) 不会触发关联的处理程序。我没有看到任何错误指示,即使我在 ContextDeleteFrames_Click 中放置了一个断点,它也不会被击中。好像根本没有与该菜单项关联的处理程序。

我已经查看了许多与上下文菜单不起作用相关的其他问题,但 none 似乎适用。是不是两个列表框嵌套有问题?

XAML:

<ListBox Name="PageListBox" ItemsSource="{Binding CurrentPack.Pages}" HorizontalAlignment="Stretch" SelectionMode="Extended">
<ListBox.Resources>
    <ContextMenu x:Key="PageContextMenu">
        <MenuItem Header="_Add" Name="ContextAddAddPage"/>
        <MenuItem Header="_Edit" Name="ContextEditPage"/>
        <MenuItem Header="_Delete Selected" Name="ContextDeletePage" Click="ContextDeletePage_Click"/>
    </ContextMenu>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="ContextMenu" Value="{StaticResource PageContextMenu}"/>
        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
        <Setter Property="HorizontalAlignment" Value="Stretch"/>
    </Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
    <DataTemplate >
        <Border  BorderThickness="2" BorderBrush="White" HorizontalAlignment="Stretch">
            <StackPanel HorizontalAlignment="Stretch">
                <Label Content="{Binding PresentationName}"/>
                <Expander  VerticalAlignment="Top" HorizontalAlignment="Stretch">
                    <Expander.Header>
                        <Label Content="{Binding FrameStatusText}"/>
                    </Expander.Header>
                    <ListBox Name="FrameListBox" ItemsSource="{Binding Frames}" HorizontalAlignment="Stretch" SelectionMode="Extended">
                        <ListBox.Resources>
                            <ContextMenu x:Key="FrameContextMenu">
                                <MenuItem Header="_Add Frame" Name="ContextAddFrame"/>
                                <MenuItem Header="_Edit Frame" Name="ContextEditFrame"/>
                                <MenuItem Header="_Delete Selected Frame(s)" Name="ContextDeleteFrames" Click="ContextDeleteFrames_Click"/>
                                <MenuItem Header="Show _Preview" Name="ContextShowPreview" Click="ContextShowPreview_Click"/>
                            </ContextMenu>
                            <Style TargetType="{x:Type ListBoxItem}">
                                <Setter Property="ContextMenu" Value="{StaticResource FrameContextMenu}"/>
                                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
                            </Style>
                        </ListBox.Resources>
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Label Content="{Binding PresentationName}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </Expander>
            </StackPanel>
        </Border>
    </DataTemplate>
</ListBox.ItemTemplate>

隐藏代码:

    private void ContextDeletePage_Click(object sender, RoutedEventArgs e)
    { //this works
        Workspace.Content.DeleteSelectedPages();
    }

    private void ContextDeleteFrames_Click(object sender, RoutedEventArgs e)
    { //this doesn't!
        Workspace.Content.DeleteSelectedFrames();
    }

不要在 DataTemplate 中使用事件。他们不会工作。

将您的第二个上下文菜单从 DataTemplate 的资源移动到 PageListBox 的资源中,如下所示:

<ListBox Name="PageListBox">
    <ListBox.Resources>
        <!-- ... other resources... -->

        <ContextMenu x:Key="FrameContextMenu">
            <MenuItem Header="_Add Frame" Name="ContextAddFrame"/>
            <MenuItem Header="_Edit Frame" Name="ContextEditFrame"/>
            <MenuItem Header="_Delete Selected Frame(s)" Click="ContextDeleteFrames_Click"/>
            <MenuItem Header="Show _Preview" Name="ContextShowPreview" Click="ContextShowPreview_Click"/>
        </ContextMenu>
    </ListBox.Resources>
</ListBox>

...或使用命令代替事件:

<MenuItem Header="_Delete Selected Frame(s)" Command="{Binding DeleteFrameCommand}"/>

其中 DeleteFrameCommandICommandRoutedCommand 类型的 属性。

如果你想使用命令,你应该知道上下文菜单不在其 PlacementTarget 的可视化树中,所以你必须使用一些帮助程序来使绑定工作(a绑定代理或 PlacementTarget.Tag 属性 等)