Xamarin.Forms JSON 对象进入列表视图
Xamarin.Forms JSON object into Listview
我正在尝试解析这个 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
}
};
}
看起来您没有在等待 sv.GetUsersAsync,我不确定结果是否会在不等待操作完成的情况下包含所有数据。
虽然可以使用任何集合和任何对象作为列表视图的数据源,但最好使用 ObservableCollection 并使您的用户 class 实现 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 是 Xamarin.Forms 中关于 mvvm 和数据加载的好文章。
编辑 2
你为什么用这么奇怪的方式使用 async/await?与其阅读 Task.Result 属性,不如使用 async/await 对。 Example.
您的异步调用不正确。如果您必须在构造函数中执行此操作(这不是执行此操作的最佳位置),您会希望使用 ContinueWith,因为不应使用 Task.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 对象并将其绑定到我在 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
}
};
}
看起来您没有在等待 sv.GetUsersAsync,我不确定结果是否会在不等待操作完成的情况下包含所有数据。
虽然可以使用任何集合和任何对象作为列表视图的数据源,但最好使用 ObservableCollection 并使您的用户 class 实现 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 是 Xamarin.Forms 中关于 mvvm 和数据加载的好文章。
编辑 2
你为什么用这么奇怪的方式使用 async/await?与其阅读 Task.Result 属性,不如使用 async/await 对。 Example.
您的异步调用不正确。如果您必须在构造函数中执行此操作(这不是执行此操作的最佳位置),您会希望使用 ContinueWith,因为不应使用 Task.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");
}
}