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

.NET MAUI传递QueryParameter时获取值为null的问题

MAUI QueryProperty传值后ViewModel内属性为null的解决方法

问题场景

我有两个使用CollectionView展示列表的页面:主页面ExploreCountriesPage和子页面ExploreRadiosPage,需要把主页面的SelectedItem作为子页面的SelectedCountry,用来填充子页面的数据。

目前遇到的问题:UI能正常显示传递过来的国家名称,但在ViewModel里调用InitializeData()加载数据时,SelectedCountry却是null。已经实现了INotifyPropertyChanged接口,但没解决问题。

主页面ViewModel代码

public class ExploreCountriesViewModel : INotifyPropertyChanged
{
    private NameAndCount selectedItem;
    public NameAndCount SelectedItem
    {
        get => selectedItem;
        set
        {
            selectedItem = value;
            RaisePropertyChanged();
        }
    }

    // ... 其他代码

    public ICommand NavigateTo => new Command(() => {
        var navParam = new Dictionary<string, object>
        {
            {"SelectedCountry", SelectedItem }
        };
        Shell.Current.GoToAsync($"{nameof(ExploreRadiosPage)}", navParam);
    });

    // ... 其他代码
}

子页面ViewModel代码

[QueryProperty(nameof(SelectedCountry), "SelectedCountry")]
public class ExploreRadiosViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName = null)
    => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    private readonly IRadioBrowserClient radioBrowserClient;
    private NameAndCount selectedCountry;
    private List<StationInfo> stations;
    public List<StationInfo> Stations
    {
        get => stations;
        set
        {
            stations = value;
            RaisePropertyChanged();
        }
    }
    public NameAndCount SelectedCountry // 从QueryParameter传值后仍为null
    {
        get => selectedCountry;
        set
        {
            selectedCountry = value;
            RaisePropertyChanged();
        }
    }
    public ExploreRadiosViewModel(IRadioBrowserClient radioBrowserClient)
    {
        this.radioBrowserClient = radioBrowserClient;

        InitializeData();
    }

    private async Task InitializeData()
    {
        try
        {
            Stations = await radioBrowserClient.Search.AdvancedAsync(new AdvancedSearchOptions
            {
                Country = SelectedCountry.Name // SelectedCountry为null!
            });
            foreach (var result in Stations)
            {
                Debug.WriteLine(result.Name);
            }

        }
        catch (Exception e)
        {
            Debug.WriteLine(e);
        }
    }
}

子页面XAML代码

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:viewmodel="clr-namespace:Rad.io.Client.MAUI.ViewModels"
             x:Class="Rad.io.Client.MAUI.Pages.ExploreRadiosPage"
             x:DataType="viewmodel:ExploreRadiosViewModel"
             xmlns:radios="clr-namespace:RadioBrowser.Models;assembly=RadioBrowser"
             Title="{Binding SelectedCountry.Name}"> <!-- 此处能正确显示国家名称 -->
    <Grid RowDefinitions="Auto, Auto">
        <Entry Grid.Row="0" Placeholder="Search"/>
        <CollectionView x:Name="RadiosList" Grid.Row="1" SelectionMode="Single" ItemsSource="{Binding Stations}">
            <!-- ... 其他布局代码 -->
        </CollectionView>
    </Grid>
</ContentPage>

问题原因

核心逻辑顺序错误:MAUI导航时,会先实例化ViewModel(执行构造函数),之后才会通过QueryProperty机制给SelectedCountry赋值。你在构造函数里直接调用InitializeData(),这时候SelectedCountry还没被赋值,自然是null。而UI能正常显示,是因为后续SelectedCountry赋值后触发了PropertyChanged,UI绑定自动更新了。

解决方法

方法1:在SelectedCountry的setter中触发数据加载

修改子页面ViewModel的SelectedCountry属性,在赋值完成后调用数据初始化方法:

public NameAndCount SelectedCountry
{
    get => selectedCountry;
    set
    {
        selectedCountry = value;
        RaisePropertyChanged();
        // 赋值完成后再加载数据,使用_避免异步方法警告
        _ = InitializeData();
    }
}

// 构造函数中移除InitializeData的调用
public ExploreRadiosViewModel(IRadioBrowserClient radioBrowserClient)
{
    this.radioBrowserClient = radioBrowserClient;
    // 删掉 InitializeData();
}

方法2:利用页面生命周期方法(推荐)

在子页面的代码后台重写OnNavigatedTo方法,确保参数传递完成后再通知ViewModel加载数据:

  1. 子页面代码后台(ExploreRadiosPage.xaml.cs):
protected override void OnNavigatedTo(NavigatedToEventArgs args)
{
    base.OnNavigatedTo(args);
    // 确认BindingContext是目标ViewModel
    if (BindingContext is ExploreRadiosViewModel vm)
    {
        _ = vm.InitializeData();
    }
}
  1. 同时修改ViewModel的构造函数,移除InitializeData()的调用:
public ExploreRadiosViewModel(IRadioBrowserClient radioBrowserClient)
{
    this.radioBrowserClient = radioBrowserClient;
    // 移除 InitializeData();
}

注意事项

  • 异步方法调用时用_ = InitializeData()或者在异步生命周期方法中用await,避免阻塞UI线程。
  • 如果使用方法1,要考虑重复赋值的情况(比如页面返回后再次导航),可以加个判断避免重复加载数据。

内容的提问来源于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.26 08:15:43