.NET MAUI页面加载时设置SelectedIndex存在延迟问题求助
问题描述
当视图显示在屏幕上时,为控件设置值会出现短暂延迟,能不能在用户看到视图之前就完成值的设置?
public UserSettingsView() { InitializeComponent(); LoadAsync(); } private async void LoadAsync() { try { // 从API加载数据 Languages = await _languageService.GetAsync(AccessToken); USStates = await _uSStateService.GetAsync(AccessToken); // 将列表分配给每个Picker的ItemSource ddlLanguages.ItemsSource = Languages; ddlUSStates.ItemsSource = USStates; // 获取用户的偏好设置 var userSettings = await _accountService.GetSettingsAsync(UserID, AccessToken); if (userSettings != null) { // 为每个Picker控件设置用户值。 // 延迟出现在这里。 ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == userSettings.LanguageID); ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == userSettings.USStateID); cbAge.IsChecked = currentSettings.AgeQualified; } } catch { await DisplayAlert("哦不!", "加载页面出错", "确定"); } }
解决方案
1. 优化加载时机与方式(推荐)
不要在构造函数中调用异步加载方法,改用页面的OnAppearing生命周期事件,同时并行加载数据提升效率,避免串行等待:
private bool _isLoaded = false; protected override async void OnAppearing() { base.OnAppearing(); if (_isLoaded) return; await LoadAsync(); _isLoaded = true; } // 将方法改为返回Task,避免async void带来的异常捕获问题 private async Task LoadAsync() { try { // 并行发起所有API请求,减少总等待时间 var loadLanguagesTask = _languageService.GetAsync(AccessToken); var loadStatesTask = _uSStateService.GetAsync(AccessToken); var loadSettingsTask = _accountService.GetSettingsAsync(UserID, AccessToken); // 等待所有请求完成 await Task.WhenAll(loadLanguagesTask, loadStatesTask, loadSettingsTask); Languages = loadLanguagesTask.Result; USStates = loadStatesTask.Result; var userSettings = loadSettingsTask.Result; // 先绑定数据源,再设置选中项 ddlLanguages.ItemsSource = Languages; ddlUSStates.ItemsSource = USStates; if (userSettings != null) { ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == userSettings.LanguageID); ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == userSettings.USStateID); cbAge.IsChecked = userSettings.AgeQualified; // 修正原代码的变量名笔误 } } catch { await DisplayAlert("哦不!", "加载页面出错", "确定"); } }
2. 预加载数据(页面跳转前准备)
如果该页面是从其他页面跳转进入,可以在跳转前提前加载所有需要的数据,再通过构造函数传递给目标页面:
跳转页面代码:
// 提前加载数据 var languages = await _languageService.GetAsync(AccessToken); var states = await _uSStateService.GetAsync(AccessToken); var userSettings = await _accountService.GetSettingsAsync(UserID, AccessToken); // 跳转到设置页面并传入已加载的数据 await Navigation.PushAsync(new UserSettingsView(languages, states, userSettings));
目标页面构造函数修改:
public UserSettingsView(List<Language> languages, List<USState> states, UserSettings userSettings) { InitializeComponent(); Languages = languages; USStates = states; ddlLanguages.ItemsSource = Languages; ddlUSStates.ItemsSource = USStates; if (userSettings != null) { ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == userSettings.LanguageID); ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == userSettings.USStateID); cbAge.IsChecked = userSettings.AgeQualified; } }
3. 采用MVVM数据绑定
通过MVVM模式将控件与ViewModel的属性绑定,提前在ViewModel中加载好数据,页面渲染时直接使用:
ViewModel示例:
public class UserSettingsViewModel : INotifyPropertyChanged { private List<Language> _languages; public List<Language> Languages { get => _languages; set { _languages = value; OnPropertyChanged(); } } private Language _selectedLanguage; public Language SelectedLanguage { get => _selectedLanguage; set { _selectedLanguage = value; OnPropertyChanged(); } } // 对应USStates和选中项、年龄勾选的属性同理实现... private bool _ageQualified; public bool AgeQualified { get => _ageQualified; set { _ageQualified = value; OnPropertyChanged(); } } public bool IsLoaded { get; set; } public async Task LoadDataAsync(string accessToken, int userId) { var loadLanguagesTask = _languageService.GetAsync(accessToken); var loadStatesTask = _uSStateService.GetAsync(accessToken); var loadSettingsTask = _accountService.GetSettingsAsync(userId, accessToken); await Task.WhenAll(loadLanguagesTask, loadStatesTask, loadSettingsTask); Languages = loadLanguagesTask.Result; USStates = loadStatesTask.Result; var settings = loadSettingsTask.Result; if (settings != null) { SelectedLanguage = Languages.FirstOrDefault(x => x.ID == settings.LanguageID); SelectedUSState = USStates.FirstOrDefault(x => x.ID == settings.USStateID); AgeQualified = settings.AgeQualified; } } // 实现INotifyPropertyChanged接口 public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
页面XAML绑定:
<Picker ItemsSource="{Binding Languages}" SelectedItem="{Binding SelectedLanguage}" /> <Picker ItemsSource="{Binding USStates}" SelectedItem="{Binding SelectedUSState}" /> <CheckBox IsChecked="{Binding AgeQualified}" />
页面代码:
private UserSettingsViewModel _viewModel; public UserSettingsView() { InitializeComponent(); _viewModel = new UserSettingsViewModel(); BindingContext = _viewModel; } protected override async void OnAppearing() { base.OnAppearing(); if (!_viewModel.IsLoaded) { await _viewModel.LoadDataAsync(AccessToken, UserID); _viewModel.IsLoaded = true; } }
内容的提问来源于stack exchange,提问作者Victor_Tlepshev
相关产品推荐
相关产品推荐

