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

UWP中动态绑定NavigationViewItem与NavigationViewItemHeader问题

解决UWP NavigationView动态生成导航项的问题

你的核心问题在于错误地将Grid和ListView直接嵌套进了NavigationView.MenuItems中——这个集合只接受NavigationViewItem、NavigationViewItemHeader、NavigationViewItemSeparator这类导航专用控件,ListView会被当作单个导航项的内容,自然只会占用单个项的空间。下面给你两种可行的解决方案,推荐用数据绑定的方式,更符合UWP的开发习惯。

方案一:数据绑定+模板选择器(推荐,MVVM友好)

这种方式通过定义数据模型,把菜单数据和UI分离,便于维护和扩展。

1. 定义导航项数据模型

先创建一个类来区分导航头部和普通导航项:

public class NavigationMenuItem
{
    // 显示文本
    public string Title { get; set; }
    // 是否是头部
    public bool IsHeader { get; set; }
    // 导航项图标(可选)
    public Symbol Icon { get; set; }
    // 页面标记,用于导航时区分目标页面
    public string PageTag { get; set; }
}

2. 准备菜单数据集合

在页面或ViewModel中创建可观察集合,并加载你的书籍数据:

using System.Collections.ObjectModel;

public ObservableCollection<NavigationMenuItem> MenuItems { get; } = new ObservableCollection<NavigationMenuItem>();

private void LoadMenuItems()
{
    // 添加"My Books"头部
    MenuItems.Add(new NavigationMenuItem { Title = "My Books", IsHeader = true });
    
    // 从你的books集合中加载书籍导航项
    foreach (var book in books.getBooks())
    {
        MenuItems.Add(new NavigationMenuItem
        {
            Title = book.Name,
            IsHeader = false,
            Icon = Symbol.Book,
            PageTag = book.Id.ToString()
        });
    }
}

3. 创建模板选择器区分头部和项

创建一个模板选择器,让NavigationView知道不同数据该用哪种UI模板:

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

public class NavigationMenuTemplateSelector : DataTemplateSelector
{
    public DataTemplate HeaderTemplate { get; set; }
    public DataTemplate ItemTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        if (item is NavigationMenuItem menuItem)
        {
            return menuItem.IsHeader ? HeaderTemplate : ItemTemplate;
        }
        return base.SelectTemplateCore(item);
    }
}

4. 修改XAML代码

在页面资源中定义模板和选择器,然后绑定NavigationView的数据源:

<Page.Resources>
    <!-- 导航头部模板 -->
    <DataTemplate x:Key="NavigationHeaderTemplate">
        <NavigationViewItemHeader Content="{Binding Title}" />
    </DataTemplate>

    <!-- 普通导航项模板 -->
    <DataTemplate x:Key="NavigationItemTemplate">
        <NavigationViewItem Content="{Binding Title}" Tag="{Binding PageTag}">
            <NavigationViewItem.Icon>
                <SymbolIcon Symbol="{Binding Icon}" />
            </NavigationViewItem.Icon>
        </NavigationViewItem>
    </DataTemplate>

    <!-- 模板选择器 -->
    <local:NavigationMenuTemplateSelector x:Key="MenuTemplateSelector"
                                          HeaderTemplate="{StaticResource NavigationHeaderTemplate}"
                                          ItemTemplate="{StaticResource NavigationItemTemplate}" />
</Page.Resources>

<!-- 修改后的NavigationView -->
<NavigationView x:Name="NavViewTester" 
                ItemInvoked="NavViewTester_ItemInvoked" 
                Loaded="NavViewTester_Loaded" 
                IsPaneToggleButtonVisible="True" 
                IsPaneOpen="True"
                MenuItemsSource="{x:Bind MenuItems}"
                ItemTemplateSelector="{StaticResource MenuTemplateSelector}">
    <!-- 导航内容区域,一般放Frame用于页面跳转 -->
    <Frame x:Name="ContentFrame" />
</NavigationView>

5. 加载数据并处理导航

在页面Loaded事件中加载菜单数据,然后处理ItemInvoked事件实现导航:

private void NavViewTester_Loaded(object sender, RoutedEventArgs e)
{
    LoadMenuItems();
}

private void NavViewTester_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
    if (args.InvokedItemContainer is NavigationViewItem item && item.Tag is string tag)
    {
        // 根据tag跳转到对应的页面,示例:
        switch (tag)
        {
            case "book1":
                ContentFrame.Navigate(typeof(BookDetailPage), tag);
                break;
            // 其他书籍的跳转逻辑
        }
    }
}

方案二:代码后台动态创建控件(快速实现)

如果不想用数据绑定,也可以直接在后台代码中创建导航控件并添加到MenuItems:

修改XAML

清空MenuItems的内容,只保留基础的NavigationView:

<NavigationView x:Name="NavViewTester" 
                ItemInvoked="NavViewTester_ItemInvoked" 
                Loaded="NavViewTester_Loaded" 
                IsPaneToggleButtonVisible="True" 
                IsPaneOpen="True">
    <Frame x:Name="ContentFrame" />
</NavigationView>

在Loaded事件中动态添加项

private void NavViewTester_Loaded(object sender, RoutedEventArgs e)
{
    // 添加头部
    var header = new NavigationViewItemHeader { Content = "My Books" };
    NavViewTester.MenuItems.Add(header);

    // 添加书籍导航项
    foreach (var book in books.getBooks())
    {
        var navItem = new NavigationViewItem
        {
            Content = book.Name,
            Tag = book.Id.ToString(),
            Icon = new SymbolIcon(Symbol.Book)
        };
        NavViewTester.MenuItems.Add(navItem);
    }
}

导航事件的处理和方案一一致,这里就不重复了。

内容的提问来源于stack exchange,提问作者J.Carden

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:14:34