如何在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
相关产品推荐
相关产品推荐

