简体   繁体   English

Xamarin.Forms JSON对象进入Listview

[英]Xamarin.Forms JSON object into Listview

I'm trying parse this JSON object and bind it to my ListView in Xamarin.Forms. 我正在尝试解析此JSON对象,并将其绑定到Xamarin.Forms中的ListView。

I'm just totally lost on how to handle it as i'm completely new to Xamarin Forms. 由于我是Xamarin Forms的新手,我对如何处理它一无所知。

Is there a easier way to do this? 有没有更简单的方法可以做到这一点?

My returned JSON Object 我返回的JSON对象

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

Here is the my Code to handle the REST json response 这是我的代码来处理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 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 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
                }
            };
        }

Your async call is not correct. 您的异步通话不正确。 If you have to do it in the constructor (which isn't the best place to do this) you would want to use ContinueWith as using Task.Result should not be used. 如果必须在构造函数中执行此操作(这不是最佳选择),则需要使用ContinueWith来使用Task.Result。 Also because the Result is a blocking call you are assigning the item source before the list view is constructed and you are getting a null reference exception. 同样,由于Result是一个阻塞调用,因此您要在构造列表视图之前分配项目源,并且会得到null引用异常。

Try this: 尝试这个:

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);
            }
        });
    }
}

A slightly better option (but not perfect either) would be to override the appearing method and mark is async. 一个更好的选择(但也不完美)是覆盖出现的方法,并且标记为异步。 This way you can use await on the async REST call method. 这样,您可以在异步REST调用方法上使用await。 Note that this would get called every time the view appears unless additional code is added. 请注意,除非添加其他代码,否则每次视图出现时都会调用此方法。

    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");
        }
    }

Looks like you are not awaiting sv.GetUsersAsync and I'm not sure if Result will contain all data without waiting for the operation to be completed. 看起来您没有在等待sv.GetUsersAsync,而且我不确定Result是否将包含所有数据,而无需等待操作完成。

Though it's fine to use any collection and any objects as data source for list view it's better to use ObservableCollection and make your User class implement INotifyPropertyChanged (take a look on Fody.PropertyChanged nuget package). 尽管可以将任何集合和任何对象用作列表视图的数据源,但最好使用ObservableCollection并让您的User类实现INotifyPropertyChanged(请看一下Fody.PropertyChanged nuget包)。

Could you share xaml with us? 您可以与我们分享xaml吗?

EDIT 1 编辑1

You define your ItemTemplate twice. 您定义两次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

Plus it's better to use MVVM with Xamarin.Forms and load your data in view-model and not in your page's constructor. 此外,最好将MVVM与Xamarin.Forms一起使用,并在视图模型而不是页面的构造函数中加载数据。 Here is good article about mvvm and data loading in Xamarin.Forms. 是一篇关于mvvm和Xamarin.Forms中的数据加载的好文章。

EDIT 2 编辑2

Why do you use async/await in such a strange way? 为什么以这种奇怪的方式使用async / await? Instead of reading Task.Result property it's better to use async/await pair. 与其阅读Task.Result属性,不如使用异步/等待对。 Example . 例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM