异步方法不是在第一次加载时绑定数据,而是在 UWP 中的第二次加载时绑定数据

本文关键字:数据 加载 绑定 第二次 UWP 异步方法 第一次 | 更新日期: 2023-09-27 18:32:39

我有一个异步方法。我正在尝试从网络上的 json 文件绑定列表视图。我正在开发一个通用的Windows平台应用程序。当我第二次打开页面时,正在加载列表视图。但是当然,我希望在第一次加载时加载列表视图。什么会导致问题?谢谢。这是我的 XAML 的代码隐藏。

 public MyPage()
    {
        this.InitializeComponent();
        Namedays =  new List<NamedayModel>();
        LoadData();
        listview1.ItemsSource = Namedays;
    }
    public async void LoadData()
    {
        Namedays = await GetAllNamedaysAsync();
    }
    private static List<NamedayModel> allNamedaysCache;
    public static async Task<List<NamedayModel>> GetAllNamedaysAsync()
    {
        if (allNamedaysCache != null)
            return allNamedaysCache;
        var client = new HttpClient();
        var stream = await client.GetStreamAsync("http://www.example.com/myfile.json");
        var serializer = new DataContractJsonSerializer(typeof(List<NamedayModel>));
        allNamedaysCache = (List<NamedayModel>)serializer.ReadObject(stream);
        return allNamedaysCache;
    }

异步方法不是在第一次加载时绑定数据,而是在 UWP 中的第二次加载时绑定数据

你做错了几件事:

  • 如果不是真的需要(例如事件(,请不要使异步无效
  • 你在构造函数中运行你的LoadData()作为 fire-forget,它不会等待(在构造函数中也是不可能的(,代码更进一步,你将 listview 的 itemssource 设置为 Namedays。您没有对 ItemsSource 使用绑定,因此当您在加载的方法中更改 Namedays 时,列表视图不会反映它。
  • 除此之外,通过为 LoadData() 中的 Namedays 分配新值,您不会更改 ListView 的 itemsSource 的值 - 它仍然指向旧集合。

在这种情况下,如果您对 ItemsSource 使用绑定,定义属性并在例如 Loaded 事件中异步加载数据,那就更好了。示例代码,XAML:

<ListView ItemsSource="{Binding Namedays}"/>

以及背后的代码:

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    private List<NamedayModel> namedays = new List<NamedayModel>();
    public List<NamedayModel> Namedays { get { return namedays; } set { namedays = value; RaiseProperty(nameof(Namedays)); } }
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = this;
        this.Loaded += MainPage_Loaded;
    }
    private async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        Namedays = await GetAllNamedaysAsync();
    }
    public static async Task<List<NamedayModel>> GetAllNamedaysAsync()
    {
        if (allNamedaysCache != null)
            return allNamedaysCache;
        var client = new HttpClient();
        var stream = await client.GetStreamAsync("http://www.tyosoft.com/namedays_hu.json");
        var serializer = new DataContractJsonSerializer(typeof(List<NamedayModel>));
        allNamedaysCache = (List<NamedayModel>)serializer.ReadObject(stream);
        return allNamedaysCache;
    }
}

作为旁注 - 如果您想在不重新分配的情况下修改它,您也可以考虑使用 ObservableCollection 而不是 List

您的listview1不知道数据,因此不会加载它们。当您第二次打开页面时,数据已加载,listview1可以显示它们。

您需要实现INotifyPropertyChanged这样的接口:

 protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler eventHandler = this.PropertyChanged;
        if (eventHandler != null)
        {
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

然后在加载数据后调用OnPropertyChanged(nameof(Namedays))