如何使用可重用样式根据其(动态)上下文菜单是否具有项目来更改控件的外观?
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>
我有一个带有动态上下文菜单的按钮(即从 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>