如何使用可重用样式根据其(动态)上下文菜单是否具有项目来更改控件的外观?

How to change a control's appearance based on whether its (dynamic) context menu has items, using a reusable Style?

我有一个带有动态上下文菜单的按钮(即从 ItemsSource 提供)。我想使用它的 ContextMenu.HasItems 属性 作为触发器在上下文菜单为空时禁用它。以下似乎不起作用,即使调试器显示绑定没有问题:

<Style x:Key="ContextMenuButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=ContextMenu.HasItems}" Value="False">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Style.Triggers>
</Style>

这样使用:

<Button Style="{StaticResource ContextMenuButtonStyle}" Content="Items" Click="ShowContext">
    <Button.ContextMenu>
        <ContextMenu ItemsSource="{Binding MyItems}" Placement="Top" VerticalOffset="-1" />
    </Button.ContextMenu>
</Button>

这总是表现得好像没有项目一样,即按钮保持禁用状态。但是,如果我注释掉该触发器,我可以立即看到上下文菜单清楚地包含此时的项目。

有趣的是,我有第二个类似的触发器,它基于 ContextMenu.IsOpen,运行良好:

        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=ContextMenu.IsOpen}" Value="True">
            <Setter Property="Background" Value="White" />
            <Setter Property="Foreground" Value="Black" />
        </DataTrigger>

所以也许问题实际上不是触发器中的绑定,而是 ItemsSource 的 querying/updating 以某种方式受到禁用状态的影响?关于如何解决此问题的任何其他想法或提示?

更新:我现在发现 Items 集合显然没有从 ItemsSource 填充,直到实际显示上下文菜单,所以这当然可以解释为什么我的 HasItems 方法不起作用。那么,有没有办法让触发器对引用的内容做出反应 ItemsSource - 但没有在样式中明确引用该源,以便它可以重新用于具有不同项目源的其他按钮?

您是否考虑过这样做?

<Style x:Key="ContextMenuButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=MyItems.Count}" Value="0">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Style.Triggers>
</Style>

好的,我在发布问题更新时才意识到显而易见的答案:

<Style x:Key="ContextMenuButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=ContextMenu.ItemsSource.Count}" Value="0">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Style.Triggers>
</Style>