Xamarin.Forms JSON 对象到 Listview

Posted

技术标签:

【中文标题】Xamarin.Forms JSON 对象到 Listview【英文标题】:Xamarin.Forms JSON object into Listview 【发布时间】:2015-05-03 23:48:38 【问题描述】:

我正在尝试解析此 JSON 对象并将其绑定到 Xamarin.Forms 中的 ListView。

我完全不知道如何处理它,因为我对 Xamarin Forms 完全陌生。

有更简单的方法吗?

我返回的 JSON 对象

[
  
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret"
  ,
  
    "id": 2,
    "name": "Ervin Howell",
    "username": "Antonette"
  
]

这是我处理 REST json 响应的代码

public class RestClient
    
        public RestClient ()
        
        

        public async Task<User[]> GetUsersAsync () 

            var client = new System.Net.Http.HttpClient ();

            client.BaseAddress = new Uri("http://jsonplaceholder.typicode.com");

            var response = client.GetAsync("users");

            var usersJson = response.Result.Content.ReadAsStringAsync().Result;

            var rootobject = JsonConvert.DeserializeObject<Rootobject>(usersJson);

            return rootobject.Users;

        
    

Users.cs

    public class Rootobject
        
            public User[] Users  get; set; 
        

        public class User
        
            public string id  get; set; 
            public string username  get; set; 
        

ListView Form Code
var sv = new RestClient ();
            var es = sv.GetUsersAsync();
            Xamarin.Forms.Device.BeginInvokeOnMainThread (() => 
                Debug.WriteLine("Found " + es.Result.Length + " users");
                listView.ItemsSource = es.Result;
            );

XAML

public ListViewPage ()
        
            Title = "Users";

            var sv = new RestClient ();
            var es = sv.GetUsersAsync();
            Xamarin.Forms.Device.BeginInvokeOnMainThread (() => 
                Debug.WriteLine("Found " + es.Result.Length + " users");
                listView.ItemsSource = es.Result;
            );


            listView = new ListView ();
            listView.ItemTemplate = new DataTemplate(typeof(TextCell));
            listView.ItemTemplate.SetBinding(TextCell.TextProperty, "username");

            listView.ItemTemplate = new DataTemplate(typeof(ItemCell));

            Content = new StackLayout  
                Children = 
                    listView
                
            ;
        

【问题讨论】:

【参考方案1】:

您的异步调用不正确。如果您必须在构造函数中执行此操作(这不是执行此操作的最佳位置),您可能希望使用 ContinueWith,因为不应使用 using Task.Result。此外,由于 Result 是一个阻塞调用,因此您在构造列表视图之前分配了项目源,并且您得到了一个空引用异常。

试试这个:

public class ListViewPage : ContentPage

    private readonly ListView listView;

    public ListViewPage()
    
        Title = "Users";

        this.listView = new ListView ItemTemplate = new DataTemplate(typeof (TextCell));
        this.listView.ItemTemplate.SetBinding(TextCell.TextProperty, "username");

        Content = new StackLayout
        
            Children =  this.listView 
        ;

        var sv = new RestClient();
        var es = sv.GetUsersAsync().ContinueWith(t =>
        
            if (t.Status == TaskStatus.RanToCompletion)
            
                Debug.WriteLine("Found 0 users.", t.Result.Length);
                Device.BeginInvokeOnMainThread(() => this.listView.ItemsSource = t.Result);
            
        );
    

一个更好的选择(但也不是完美的)是覆盖出现的方法并且标记是异步的。这样您就可以在异步 REST 调用方法上使用 await。请注意,除非添加其他代码,否则每次视图出现时都会调用它。

    protected override async void OnAppearing()
    
        base.OnAppearing();

        try
        
            var sv = new RestClient();
            // activate/show spinner here
            this.listView.ItemsSource = await sv.GetUsersAsync();
            // inactivate/hide spinner here
        
        catch (Exception exception)
        
            this.DisplayAlert("Error", exception.Message, "OK");
        
    

【讨论】:

我应该如何实现一个进度微调器(思考微调器),以便视图快速加载并仅显示微调器,直到它加载 JSON? 我编辑了 OnAppearing 重载以显示您将显示/隐藏微调器的位置。这是指标的 API:iosapi.xamarin.com/?link=T%3aXamarin.Forms.ActivityIndicator 只是一个小修正,您可能希望在 try-catch 的 finally 块中停用微调器,以便在出现错误时将其隐藏。 仅供参考,我在一个页面上有 2 个异步 API 调用(差异域)。我认为快速调用可以在构造函数中的 Device.BeginInvokeOnMainThread 中运行,而在 OnAppearing 中可以在笨重的调用中运行。我必须将两者都放入 OnAppearing 以使页面始终如一地工作。有趣的是,在修复之前,listView 没有在每个页面加载时显示数据的模式。干杯@SKall。【参考方案2】:

看起来您没有在等待 sv.GetUsersAsync,我不确定 Result 是否会在不等待操作完成的情况下包含所有数据。

虽然可以使用任何集合和任何对象作为列表视图的数据源,但最好使用 ObservableCollection 并使您的 User 类实现 INotifyPropertyChanged(查看 Fody.PropertyChanged nuget 包)。

你能和我们分享一下 xaml 吗?

编辑 1

你定义了你的 ItemTemplate 两次。

listView.ItemTemplate = new DataTemplate(typeof(TextCell)); //first definition
listView.ItemTemplate.SetBinding(TextCell.TextProperty, "username");

listView.ItemTemplate = new DataTemplate(typeof(ItemCell)); //second definition, remove it

另外,最好将 MVVM 与 Xamarin.Forms 一起使用,并将数据加载到视图模型中,而不是在页面的构造函数中。 Here 是关于 mvvm 和 Xamarin.Forms 中数据加载的好文章。

编辑 2

你为什么用这种奇怪的方式使用 async/await?与其读取 Task.Result 属性,不如使用 async/await 对。 Example.

【讨论】:

现已添加 XAML。但我很想知道是否有更简单的方法来加载 JSON 并将其绑定到我的 ListView 添加了关于异步/等待的评论。抱歉,这只是您的使用方式。 完全没有,我只是在网上找到了一个这样做的例子。

以上是关于Xamarin.Forms JSON 对象到 Listview的主要内容,如果未能解决你的问题,请参考以下文章

无法反序列化当前 JSON 对象,xamarin.forms 中的错误

我在 Xamarin.forms 中遇到数据绑定问题

如何将json.net添加到Xamarin Forms,本地项目或PCL上?

调试器在解析 Rest API 响应 HttpClient、Xamarin Forms 时停止

如何在我的 Xamarin Forms 应用程序上本地保存一些用户数据?

Xamarin Forms ListView 绑定到 Observable 集合中的子对象列表