You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF:设置当前页面对应MenuItem的背景色(非鼠标悬停)

解决方案

核心问题分析

你直接设置MenuItem.Background无效,是因为自定义的ControlTemplate里没有绑定MenuItem的Background属性,模板内的StackPanel样式完全独立于MenuItem本身的属性。另外,IsFocused属性不适合标记“当前页面对应项”——它仅表示控件是否获得键盘焦点,切换页面时无法稳定保持这个状态。

实现步骤

1. 添加自定义附加属性

创建一个附加属性来标记当前页面对应的MenuItem,替代IsFocused:

Public Class MenuItemExtensions
    ' 定义附加属性IsActivePage,用于标记是否为当前页面的菜单项
    Public Shared ReadOnly IsActivePageProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("IsActivePage", GetType(Boolean), GetType(MenuItemExtensions), New PropertyMetadata(False))

    Public Shared Sub SetIsActivePage(element As MenuItem, value As Boolean)
        element.SetValue(IsActivePageProperty, value)
    End Sub

    Public Shared Function GetIsActivePage(element As MenuItem) As Boolean
        Return CBool(element.GetValue(IsActivePageProperty))
    End Function
End Class

2. 修改ControlTemplate,添加活跃状态触发器

在XAML的模板中,通过DataTrigger绑定附加属性,实现活跃状态的背景色切换:

<!-- 注意添加命名空间,将local替换为你的项目命名空间 -->
<StackPanel Name="spMainNav" xmlns:local="clr-namespace:YourProjectNamespace">
    <StackPanel.Resources>
        <ControlTemplate x:Key="VsMenuSub" TargetType="MenuItem">
            <StackPanel>
                <Label Content="{TemplateBinding Header}"  Foreground="White" />
                <StackPanel.Style>
                    <Style TargetType="StackPanel">
                        <Style.Triggers>
                            <!-- 鼠标悬停样式保持不变 -->
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="Red" />
                            </Trigger>
                            <!-- 绑定附加属性,标记当前页面菜单项 -->
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:MenuItemExtensions.IsActivePage)}" Value="True">
                                <Setter Property="Background" Value="DarkRed" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Style>
            </StackPanel>
        </ControlTemplate>
    </StackPanel.Resources>

    <MenuItem Name="ProjectList" Header="Project List" Template="{StaticResource VsMenuSub}" Click="ProjectList_Click" />
    <MenuItem Header="About" Template="{StaticResource VsMenuSub}" Click="About_Click" />
    <MenuItem Header="Exit" Template="{StaticResource VsMenuSub}" Click="Exit_Click" />
</StackPanel>

3. 重构后台代码,更新附加属性

修改HighlightMenuItem方法,通过设置附加属性来标记活跃项,同时重置其他项的状态:

Public Shared Sub HighlightMenuItem(sender As MenuItem)
    Dim sp As StackPanel = sender.Parent

    ' 重置所有菜单项的活跃状态和标题
    For Each child In sp.Children
        If TypeOf child Is MenuItem Then
            Dim mi As MenuItem = CType(child, MenuItem)
            MenuItemExtensions.SetIsActivePage(mi, False)
            ' 恢复原始标题(移除之前添加的**)
            If mi.Header.ToString().StartsWith("** ") Then
                mi.Header = mi.Header.ToString().Substring(3)
            End If
        End If
    Next

    ' 设置当前菜单项为活跃状态
    MenuItemExtensions.SetIsActivePage(sender, True)
    ' 添加标题标记
    If Not sender.Header.ToString().StartsWith("** ") Then
        sender.Header = "** " & sender.Header
    End If
End Sub

原理说明

  • 附加属性IsActivePage专门用于标记“当前页面对应的菜单项”,逻辑更精准,不受焦点状态影响。
  • 模板内的DataTrigger通过RelativeSource绑定到父级MenuItem的附加属性,当属性值为True时自动切换背景色。
  • 后台代码负责维护所有菜单项的活跃状态,确保同一时间只有一个项处于活跃状态。

内容的提问来源于stack exchange,提问作者ElectricFrankincense

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:26:05