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

如何在ViewModel间传递变量?加密货币详情页初始化问题

解决CurrencyDetailsPageViewModel初始化Markets的问题

你的核心问题是ViewModel构造时Currency还没赋值,导致调用GetTopMarketsAsync时Currency.Id为空。下面是几个可行的解决方法:

方案1:把Currency作为构造参数传入

最直接的方式,让ViewModel在构造时就拿到Currency,避免null问题。

修改ViewModel:

public class CurrencyDetailsPageViewModel
{
    public IServiceProvider ServiceProvider { get; }
    public INavigationService NavigationService { get; }
    public ICryptocurrencyService CryptocurrencyService { get; }
    public Currency Currency { get; }
    public List<Market> Markets { get; }

    // 构造函数新增Currency参数
    public CurrencyDetailsPageViewModel(IServiceProvider serviceProvider, 
                                       INavigationService navigationService, 
                                       ICryptocurrencyService cryptocurrencyService,
                                       Currency currency)
    {
        ServiceProvider = serviceProvider;
        NavigationService = navigationService;
        CryptocurrencyService = cryptocurrencyService;
        Currency = currency;
        // 用GetAwaiter().GetResult()替代.Result,减少死锁风险
        Markets = cryptocurrencyService.GetTopMarketsAsync(currency.Id).GetAwaiter().GetResult();
    }
}

修改调用代码:

private void OnCurrencyClick(object selectedCurrency)
{
    var currency = (Currency)selectedCurrency;
    // 直接传入Currency创建ViewModel
    var detailsViewModel = new CurrencyDetailsPageViewModel(
        _serviceProvider,
        _navigationService,
        _serviceProvider.GetRequiredService<ICryptocurrencyService>(),
        currency
    );

    var detailsPage = new CurrencyDetailsPage(detailsViewModel);
    detailsPage.DataContext = detailsViewModel;
    _navigationService.NavigateTo(detailsPage);
}

如果你的DI容器支持传递参数(比如Autofac),也可以用容器解析:

var detailsViewModel = _serviceProvider.GetRequiredService<CurrencyDetailsPageViewModel>(
    new TypedParameter(typeof(Currency), currency)
);

方案2:通过Currency属性Setter触发异步加载

给Currency属性加Setter逻辑,赋值后自动加载Markets,同时实现INotifyPropertyChanged让UI更新。

修改ViewModel:

public class CurrencyDetailsPageViewModel : INotifyPropertyChanged
{
    public IServiceProvider ServiceProvider { get; }
    public INavigationService NavigationService { get; }
    public ICryptocurrencyService CryptocurrencyService { get; }

    private Currency _currency;
    public Currency Currency
    {
        get => _currency;
        set
        {
            if (_currency != value)
            {
                _currency = value;
                OnPropertyChanged(nameof(Currency));
                // 赋值后异步加载Markets,用_ = 避免编译器警告
                _ = LoadMarketsAsync();
            }
        }
    }

    private List<Market> _markets;
    public List<Market> Markets
    {
        get => _markets;
        set
        {
            _markets = value;
            OnPropertyChanged(nameof(Markets));
        }
    }

    public CurrencyDetailsPageViewModel(IServiceProvider serviceProvider, 
                                       INavigationService navigationService, 
                                       ICryptocurrencyService cryptocurrencyService)
    {
        ServiceProvider = serviceProvider;
        NavigationService = navigationService;
        CryptocurrencyService = cryptocurrencyService;
    }

    private async Task LoadMarketsAsync()
    {
        if (Currency == null) return;
        // 异步加载并更新Markets
        Markets = await CryptocurrencyService.GetTopMarketsAsync(Currency.Id).ConfigureAwait(false);
    }

    // 实现INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

调用代码无需修改:

还是你原来的代码,赋值Currency后会自动触发加载。

方案3:添加显式初始化方法

在ViewModel里加一个InitializeAsync方法,赋值Currency后手动调用加载Markets。

修改ViewModel:

public class CurrencyDetailsPageViewModel
{
    public IServiceProvider ServiceProvider { get; }
    public INavigationService NavigationService { get; }
    public ICryptocurrencyService CryptocurrencyService { get; }
    public Currency Currency { get; set; }
    public List<Market> Markets { get; set; }

    public CurrencyDetailsPageViewModel(IServiceProvider serviceProvider, 
                                       INavigationService navigationService, 
                                       ICryptocurrencyService cryptocurrencyService)
    {
        ServiceProvider = serviceProvider;
        NavigationService = navigationService;
        CryptocurrencyService = cryptocurrencyService;
    }

    public async Task InitializeAsync()
    {
        if (Currency == null) 
            throw new InvalidOperationException("必须先设置Currency再初始化");
        Markets = await CryptocurrencyService.GetTopMarketsAsync(Currency.Id).ConfigureAwait(false);
    }
}

修改调用代码:

把事件处理方法改成async void,调用初始化方法:

private async void OnCurrencyClick(object selectedCurrency)
{
    var currency = (Currency)selectedCurrency;
    var detailsViewModel = _serviceProvider.GetRequiredService<CurrencyDetailsPageViewModel>();
    detailsViewModel.Currency = currency;
    // 等待初始化完成
    await detailsViewModel.InitializeAsync();
    var detailsPage = new CurrencyDetailsPage(detailsViewModel);
    detailsPage.DataContext = detailsViewModel;
    _navigationService.NavigateTo(detailsPage);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:00:59