【问题标题】:Async method binds data not on firstload but on second load in UWP异步方法不是在 UWP 中的第一次加载而是在第二次加载时绑定数据
【发布时间】:2016-01-29 19:43:52
【问题描述】:

我有一个异步方法。我正在尝试从 web 上的 json 文件绑定 listview。 我正在开发一个通用 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;
    }

【问题讨论】:

    标签: c# xaml async-await uwp


    【解决方案1】:

    你做错了几件事:

    • 如果不是真的需要(例如事件),不要使 async void
    • 您在构造函数中将LoadData() 作为fire-forget 运行,它不会等待(在构造函数中也是不可能的),代码更进一步,您将listview 的itemssource 设置为命名日。您没有为 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

    【讨论】:

    • 谢谢罗马兹。但是VS在RaiseProperty的这个代码块中给了我“需要对象引用”错误||公共静态列表 Namedays { get { return namedays; } 设置 {namedays = 值; RaiseProperty(nameof(Namedays)); } } ||
    • @oneNic​​eFriend 是的,我已经把代码放在了我的脑海中。您的列表不能是静态的 - PropertyChanged 事件 与类实例相关联,因此它不能是静态的。
    • @oneNic​​eFriend 您需要为您的 ListView 提供 ItemTemplate 并在定义的 DataTemplate 中绑定到合适的属性您的 NameDayModelThis answer may help little.
    • @oneNic​​eFriend 一切都取决于您的需求 - 您可以执行一次,或者每次用户加载页面时执行一次,但如果数据没有更改,那么我认为没有必要再次加载它。跨度>
    • @oneNic​​eFriend 调试一下。 Loaded 事件可以多次触发,但我认为您已经通过if (allNamedaysCache != null) return allNamedaysCache; 处理了这个问题。对于此类问题,请始终调试您的程序 - 您会比写评论更快地找到答案。
    【解决方案2】:

    您的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))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      • 2015-11-26
      • 2021-08-01
      • 2013-04-03
      • 1970-01-01
      相关资源
      最近更新 更多