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

WinUI NavigationView:Frame显示页面遇空引用错误及数据加载需求

问题分析与解决方案

核心问题定位

你遇到的"对象引用未设置为对象实例"错误,主要来自两个关键原因:

  1. 页面构造函数依赖无法解析:ExploreCountriesPage只有带ExploreCountriesViewModel参数的构造函数,但WinUI的Frame.Navigate默认会尝试调用无参构造函数创建页面,导致实例创建失败,触发空引用异常。
  2. 异步初始化时机不当:在ExploreCountriesViewModel的构造函数中直接调用异步方法InitializeDataAsync(),无法等待异步操作完成,不仅会导致数据加载时机不可控,还可能引发未捕获的异常。

分步解决方案

1. 修复页面导航的依赖注入问题

方式一:通过DI容器直接解析页面实例

首先在App.cs中注册页面类型:

private IServiceProvider RegisterServices()
{
    var serviceCollection = new ServiceCollection();

    serviceCollection.AddSingleton<IRadioBrowserClient>(new RadioBrowserClient(apiUrl: "de1.api.radio-browser.info"));
    serviceCollection.AddSingleton<ExploreCountriesViewModel>();
    serviceCollection.AddTransient<ExploreCountriesPage>(); // 注册页面

    return serviceCollection.BuildServiceProvider();
}

然后修改MainWindow.cs,延迟到窗口加载完成后,从DI容器获取页面实例再导航:

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
        this.Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var container = ((App)Application.Current).Container;
        var page = container.GetService<ExploreCountriesPage>();
        ContentFrame.Navigate(page);
    }
}

这种方式下,DI容器会自动将ExploreCountriesViewModel注入到页面的构造函数中,无需手动传递参数。

方式二:通过导航参数传递ViewModel

如果不想注册页面到DI容器,可以保留原页面构造函数,修改MainWindow.cs传递ViewModel:

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    var container = ((App)Application.Current).Container;
    var viewModel = container.GetService<ExploreCountriesViewModel>();
    ContentFrame.Navigate(typeof(ExploreCountriesPage), viewModel);
}

同时修改ExploreCountriesPage.cs,在导航时接收参数:

public sealed partial class ExploreCountriesPage : Page
{
    public ExploreCountriesViewModel CountriesViewModel { get; set; }

    // 保留带参数的构造函数,同时支持导航参数传递
    public ExploreCountriesPage()
    {
        this.InitializeComponent();
    }

    public ExploreCountriesPage(ExploreCountriesViewModel viewModel)
    {
        this.InitializeComponent();
        CountriesViewModel = viewModel;
        DataContext = CountriesViewModel;
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        if (e.Parameter is ExploreCountriesViewModel viewModel && CountriesViewModel == null)
        {
            CountriesViewModel = viewModel;
            DataContext = CountriesViewModel;
        }
        _ = CountriesViewModel.InitializeDataAsync();
    }
}

2. 调整ViewModel异步初始化逻辑

移除ExploreCountriesViewModel构造函数中的异步方法调用,改为在页面导航完成后触发:

public ExploreCountriesViewModel(IRadioBrowserClient radioBrowserClient)
{
    this.radioBrowserClient = radioBrowserClient;
    // 移除这里的 InitializeDataAsync(); 调用
}

确保数据加载操作在页面绑定完成后执行,避免数据未就绪时的绑定异常。

3. 优化NavigationView菜单导航逻辑

如果需要通过NavigationView的菜单切换页面,同样使用DI容器解析实例:

private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
    if (args.SelectedItem is NavigationViewItem item)
    {
        var tag = item.Tag.ToString();
        Page page = null;
        var container = ((App)Application.Current).Container;
        
        switch(tag)
        {
            case "Explore":
                page = container.GetService<ExploreCountriesPage>();
                break;
            // 其他页面的处理逻辑
        }
        
        if(page != null && ContentFrame.Content != page)
        {
            ContentFrame.Navigate(page);
        }
    }
}

最终效果

完成上述修改后,MainWindow的ContentFrame会成功加载ExploreCountriesPage,页面显示时会自动触发数据加载,同时解决了空引用异常问题。

内容的提问来源于stack exchange,提问作者Sisimośki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:37:21