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

WinUI 3嵌套标签导航实现咨询:NavigationView适配折叠模式

可行方案推荐:自定义NavigationViewItem或动态切换模板

基于NavigationViewItem自定义控件的方案完全可行,而且是贴合你需求的最优方向之一。下面给两种简洁可复用的实现思路:

方案一:修改NavigationViewItem的ControlTemplate(原生适配,复用性强)

直接修改默认NavigationViewItem的模板,通过VisualState适配Pane的不同显示模式,无需额外自定义控件:

  1. 提取默认模板:使用Blend打开WinUI项目,右键NavigationViewItem -> 编辑模板 -> 编辑副本,生成默认ControlTemplate。
  2. 添加状态切换逻辑:在模板的VisualStateManager中,针对NavigationViewPaneCompact和NavigationViewPaneExpanded状态,控制文本、下划线的显示:
    • 展开模式(Expanded):显示图标+文本,给选中项添加下划线(用Border或Rectangle实现,绑定IsSelected属性控制可见性和样式)
    • 折叠模式(Compact):隐藏文本,仅保留图标,保持垂直布局

关键XAML代码片段:

<ControlTemplate TargetType="NavigationViewItem">
    <!-- 保留原有模板基础结构 -->
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="PaneDisplayModeStates">
            <VisualState x:Name="NavigationViewPaneExpanded">
                <VisualState.Setters>
                    <Setter Target="ContentPresenter.Visibility" Value="Visible"/>
                    <Setter Target="UnderlineBorder.Visibility" Value="Visible"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="NavigationViewPaneCompact">
                <VisualState.Setters>
                    <Setter Target="ContentPresenter.Visibility" Value="Collapsed"/>
                    <Setter Target="UnderlineBorder.Visibility" Value="Collapsed"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
        <VisualStateGroup x:Name="SelectionStates">
            <VisualState x:Name="Selected">
                <VisualState.Setters>
                    <Setter Target="UnderlineBorder.Background" Value="{ThemeResource SystemAccentColor}"/>
                    <!-- 可补充其他选中态样式,如文本颜色 -->
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="Unselected"/>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!-- 新增下划线元素,嵌入原有布局 -->
    <Grid>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
            <FontIcon x:Name="IconElement" Glyph="{TemplateBinding Icon}" Margin="0,0,8,0"/>
            <ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}"/>
        </StackPanel>
        <Border x:Name="UnderlineBorder" Height="2" Margin="0,0,0,-2" VerticalAlignment="Bottom" Background="Transparent" Visibility="Collapsed"/>
    </Grid>
</ControlTemplate>
  1. 全局应用模板:将修改后的模板放到Application.Resources中,所有NavigationViewItem会自动应用该样式。

方案二:动态切换ContentTemplate(快速实现,灵活度高)

通过监听NavigationView的PaneDisplayModeChanged事件,给每个NavigationViewItem切换不同的内容模板:

  1. 定义两种DataTemplate:在XAML资源中分别定义展开和折叠模式的模板:
<Page.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    
    <DataTemplate x:Key="ExpandedItemTemplate">
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
            <FontIcon Glyph="{Binding Icon}"/>
            <TextBlock x:Name="TitleText" Text="{Binding Title}" Margin="8,0,0,0"/>
            <Border Height="2" Width="{Binding ActualWidth, ElementName=TitleText}" VerticalAlignment="Bottom" 
                    Background="{ThemeResource SystemAccentColor}" 
                    Visibility="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=NavigationViewItem}, Converter={StaticResource BooleanToVisibilityConverter}}"/>
        </StackPanel>
    </DataTemplate>
    
    <DataTemplate x:Key="CompactItemTemplate">
        <FontIcon Glyph="{Binding Icon}" VerticalAlignment="Center"/>
    </DataTemplate>
</Page.Resources>
  1. 绑定MenuItems数据源:用ViewModel绑定NavigationView的MenuItems,每个项包含Icon、Title属性:
public class NavItemViewModel
{
    public string Icon { get; set; }
    public string Title { get; set; }
}

// 后台初始化数据源
private void Page_Loaded(object sender, RoutedEventArgs e)
{
    MainNav.MenuItemsSource = new List<NavItemViewModel>
    {
        new NavItemViewModel { Icon = "\uE80F", Title = "首页" },
        new NavItemViewModel { Icon = "\uE81F", Title = "设置" },
        new NavItemViewModel { Icon = "\uE82E", Title = "统计" }
    };
}
  1. 监听Pane模式变化:在后台代码中切换模板:
private void MainNav_PaneDisplayModeChanged(NavigationView sender, NavigationViewPaneDisplayModeChangedEventArgs args)
{
    var targetTemplate = sender.PaneDisplayMode == NavigationViewPaneDisplayMode.Expanded 
        ? Resources["ExpandedItemTemplate"] as DataTemplate 
        : Resources["CompactItemTemplate"] as DataTemplate;

    foreach (var item in sender.MenuItems)
    {
        if (item is NavigationViewItem navItem)
        {
            navItem.ContentTemplate = targetTemplate;
        }
    }
}

注意事项

  • 方案一需兼容NavigationView的所有Pane模式(如Minimal),可按需添加对应的VisualState。
  • 下划线样式可根据设计需求调整颜色、宽度、位置,建议绑定主题资源保证风格统一。
  • 方案二中,若MenuItems动态加载,需在加载完成后同步执行模板切换逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:18:27