2015-03-03 4 views
2

Я пытаюсь разобрать этот объект JSON и связать его с моим ListView в Xamarin.Forms.Xamarin.Forms Объект JSON в 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 
       } 
      }; 
     } 

ответ

3

Ваш асинхронный вызов неправильный. Если вам нужно сделать это в конструкторе (это не лучшее место для этого), вы бы хотели использовать 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); 
      } 
     }); 
    } 
} 

Несколько лучший вариант (но не идеален) было бы переопределить метод появляющийся и метка асинхронной. Таким образом, вы можете использовать await для метода вызова async REST. Обратите внимание, что это будет вызываться каждый раз, когда появится представление, если не добавлен дополнительный код.

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

Как я должен использовать счетчик прогресса (мышление spinner), чтобы View быстро загружался и показывал только счетчик, пока он не загрузил JSON? – dasmikko

+0

Я отредактировал перегрузку OnAppearing, чтобы показать, где вы будете показывать/скрывать счетчик. Вот API для индикатора: http://iosapi.xamarin.com/?link=T%3aXamarin.Forms.ActivityIndicator – SKall

+0

Спасибо за помощь! – dasmikko

0

Похоже, вы не ожидаете sv.GetUsersAsync, и я не уверен, что результат будет содержать все данные, не дожидаясь завершения операции.

Несмотря на то, что использовать любую коллекцию и любые объекты в качестве источника данных для просмотра списка лучше использовать ObservableCollection и сделать ваш пользовательский класс реализацией INotifyPropertyChanged (посмотрите на пакет Fody.PropertyChanged nuget).

Не могли бы вы поделиться с нами xaml?

EDIT 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.

EDIT 2

Почему вы используете асинхронной/Await таким странным образом? Вместо чтения свойства Task.Result лучше использовать пару async/wait. Example.

+0

Добавили XAML сейчас. Но я хотел бы знать, есть ли более простой способ загрузить JSON при загрузке и связать его с моим ListView. – dasmikko

+0

Отредактированный мой ответ. У вас есть ошибка в коде. –

+0

Добавлен комментарий о async/await. Извините, если это ваш стиль использования. –

Смежные вопросы