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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:41:05