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

WinUI 3:点击NavigationViewItem自动跳转至子项的实现问题

问题背景

我创建了一个包含多个项及带子菜单项的NavigationView,相关XAML代码如下:

<NavigationView.MenuItems>
    <NavigationViewItem x:Uid="Home" helpers:NavigationHelper.NavigateTo="Program.ViewModel.HomeViewModel">
    </NavigationViewItem>
    <NavigationViewItem x:Uid="List" helpers:NavigationHelper.NavigateTo="Program.ViewModel.ListViewModel">
    </NavigationViewItem>
    <NavigationViewItem x:Uid="Details" helpers:NavigationHelper.NavigateTo="Program.ViewModel.DetailsViewModel">
    <NavigationViewItem.MenuItems>
        <NavigationViewItem x:Name="SummaryViewItem" x:Uid="Details_Summary" helpers:NavigationHelper.NavigateTo="Program.ViewModel.SummaryViewModel">
        </NavigationViewItem>
        <NavigationViewItem x:Uid="Details_Distances" helpers.NavigationHelpers.NavigateTo="Program.ViewModel.DistancesViewModel">
        </NavigationViewItem>
        <NavigationViewItem x:Uid="Details_Location" helpers.NavigationHelper.NavigateTo="Program.ViewModel.LocationViewModel">
        </NavigationViewItem>
    </NavigationViewItem.MenuItems>
    </NavigationViewItem>
</NavigationView.MenuItems>

其中DetailsViewModel负责为子页面收集数据,而Details页面本身为空;子页面包含视图和字段用于规整展示信息。需求是:当用户点击Details导航项时,程序先执行对应的ViewModel的数据收集逻辑,再自动导航至Summary页面。

尝试的实现

我在DetailsViewModel中添加了如下代码:

public async void OnNavigatedToAsync(object parameter)
{
    //Other functions
    
    NavigationHelper.SetNavigateTo(ShellPage.SummaryNavigationItem, typeof(SummaryViewModel).FullName);
}

并在Shell的代码后置中添加代码以暴露SummaryViewItem:

public static NavigationViewItem SummaryNavigationItem;

public ShellPage(ShellViewModel viewModel) {

    SummaryNavigationItem = SummaryViewItem;
}

但当前效果是仍显示空白的Details页面,并未导航至Summary页面。

补充信息:NavigationHelper代码(复制自WinUI 3示例应用):

public static void SetNavigateTo(NavigationViewItem item, string value) => item.SetValue(NavigateToProperty, value);

public static readonly DependencyProperty NavigateToProperty =
        DependencyProperty.RegisterAttached("NavigateTo", typeof(string), typeof(NavigationHelper), new PropertyMetadata(null));

解决方案

你的核心问题是只设置了SummaryViewItem的NavigateTo属性,但没有主动触发导航操作;同时直接在ViewModel中操作UI元素也不符合MVVM规范。以下是两种可行的实现方式:

方式一:直接触发导航并同步选中状态

在DetailsViewModel完成数据收集后,调用导航服务跳转到SummaryViewModel,同时更新NavigationView的选中项:

public async void OnNavigatedToAsync(object parameter)
{
    // 执行数据收集逻辑,确保异步操作完成
    await CollectSubPageData();

    // 获取项目中的导航服务实例(根据实际结构调整,比如依赖注入或静态引用)
    var navigationService = App.GetService<INavigationService>();
    
    // 导航到SummaryViewModel
    await navigationService.NavigateToAsync(typeof(SummaryViewModel).FullName);

    // 同步NavigationView的选中状态
    if (ShellPage.SummaryNavigationItem != null && ShellPage.Instance.MainNavigationView != null)
    {
        ShellPage.Instance.MainNavigationView.SelectedItem = ShellPage.SummaryNavigationItem;
    }
}

注意:需要在ShellPage中添加公开的NavigationView引用:

public NavigationView MainNavigationView { get; private set; }
public static ShellPage Instance { get; private set; }

public ShellPage(ShellViewModel viewModel)
{
    InitializeComponent();
    Instance = this;
    MainNavigationView = this.FindName("MainNavView") as NavigationView;
    // 延迟获取子项引用,避免初始化时为空
    Loaded += (s, e) => SummaryNavigationItem = SummaryViewItem;
}

方式二:基于MVVM的消息通知实现(更优雅)

  1. 在ShellViewModel中维护SelectedNavigationItem属性,绑定到NavigationView:
<NavigationView x:Name="MainNavView" SelectedItem="{x:Bind ViewModel.SelectedNavigationItem, Mode=TwoWay}">
private NavigationViewItem _selectedNavigationItem;
public NavigationViewItem SelectedNavigationItem
{
    get => _selectedNavigationItem;
    set => SetProperty(ref _selectedNavigationItem, value);
}
  1. 使用CommunityToolkit.Mvvm的消息机制,在DetailsViewModel完成数据后发送切换消息:
// DetailsViewModel
using CommunityToolkit.Mvvm.Messaging;

public async void OnNavigatedToAsync(object parameter)
{
    await CollectSubPageData();
    // 发送导航切换消息
    WeakReferenceMessenger.Default.Send(new NavigateToSummaryMessage());
}

// 定义消息类
public class NavigateToSummaryMessage { }
  1. 在ShellViewModel中注册消息,处理导航切换:
using CommunityToolkit.Mvvm.Messaging;

public ShellViewModel()
{
    WeakReferenceMessenger.Default.Register<NavigateToSummaryMessage>(this, (recipient, message) =>
    {
        // 设置选中SummaryViewItem,自动触发导航(依赖NavigationView的SelectionChanged事件绑定)
        SelectedNavigationItem = ShellPage.SummaryNavigationItem;
    });
}
  1. 确保NavigationView的SelectionChanged事件绑定了导航逻辑:
private void MainNavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
    if (args.SelectedItem is NavigationViewItem item)
    {
        var navigateTo = NavigationHelper.GetNavigateTo(item);
        if (!string.IsNullOrEmpty(navigateTo))
        {
            _navigationService.NavigateToAsync(navigateTo);
        }
    }
}

关键注意事项

  • 避免在ViewModel中直接操作UI元素,优先使用绑定或消息机制,遵循MVVM设计原则。
  • 确保数据收集的异步操作完成后再触发导航,使用await等待任务结束。
  • 延迟获取SummaryViewItem的引用(比如在Loaded事件中),避免初始化时元素尚未加载导致空引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:57:37