Cross Platform Xamarin MVVM ListView binding to ViewModel List not working
-
I am trying to implement a MVVM ContentPage with a ListView that needs to bind to populated generic list of XML model objects in a ViewModel but the binding fails. The code that is shown calls an API that does return a valid list of XML data. The same code works fine when the binding is done directly in the code behind of the XAML Xamarin contentpage by setting the ItemSource in the codebehind. As said, the problem only happens when trying to pass the ListView through the ViewModel assigned to the contentpage. I have stepped through the code in the ViewModel and the ListView is populated successfully but the binding just doesn't work. I have other controls that are on the page not shown that the model binding does work for but the only control that doesn't work is the ListView. The code is shown below: ViewModel:
namespace RestDemo.ViewModel
{public class ViewModel : INotifyPropertyChanged { public ViewModel () { GetRequest(); } List \_objPizzaList; public List ObjPizzaList { get { return \_objPizzaList; } set { if (\_objPizzaList != value) { \_objPizzaList = value; OnPropertyChanged("ObjPizzaList"); } } } public async void GetRequest() { if (NetworkCheck.IsInternet()) { Uri geturi = new Uri("http://api.androidhive.info/pizza/?format=xml"); //replace your xml url HttpClient client = new HttpClient(); HttpResponseMessage responseGet = await client.GetAsync(geturi); string response = await responseGet.Content.ReadAsStringAsync(); //Xml Parsing ObjPizzaList = new List(); XDocument doc = XDocument.Parse(response); foreach (var item in doc.Descendants("item")) { XmlPizzaDetails ObjPizzaItem = new XmlPizzaDetails(); ObjPizzaItem.ID = item.Element("id").Value.ToString(); ObjPizzaItem.Name = item.Element("name").Value.ToString(); ObjPizzaItem.Cost = item.Element("cost").Value.ToString(); ObjPizzaItem.Description = item.Element("description").Value.ToString(); ObjPizzaList.Add(ObjPizzaItem);
-
I am trying to implement a MVVM ContentPage with a ListView that needs to bind to populated generic list of XML model objects in a ViewModel but the binding fails. The code that is shown calls an API that does return a valid list of XML data. The same code works fine when the binding is done directly in the code behind of the XAML Xamarin contentpage by setting the ItemSource in the codebehind. As said, the problem only happens when trying to pass the ListView through the ViewModel assigned to the contentpage. I have stepped through the code in the ViewModel and the ListView is populated successfully but the binding just doesn't work. I have other controls that are on the page not shown that the model binding does work for but the only control that doesn't work is the ListView. The code is shown below: ViewModel:
namespace RestDemo.ViewModel
{public class ViewModel : INotifyPropertyChanged { public ViewModel () { GetRequest(); } List \_objPizzaList; public List ObjPizzaList { get { return \_objPizzaList; } set { if (\_objPizzaList != value) { \_objPizzaList = value; OnPropertyChanged("ObjPizzaList"); } } } public async void GetRequest() { if (NetworkCheck.IsInternet()) { Uri geturi = new Uri("http://api.androidhive.info/pizza/?format=xml"); //replace your xml url HttpClient client = new HttpClient(); HttpResponseMessage responseGet = await client.GetAsync(geturi); string response = await responseGet.Content.ReadAsStringAsync(); //Xml Parsing ObjPizzaList = new List(); XDocument doc = XDocument.Parse(response); foreach (var item in doc.Descendants("item")) { XmlPizzaDetails ObjPizzaItem = new XmlPizzaDetails(); ObjPizzaItem.ID = item.Element("id").Value.ToString(); ObjPizzaItem.Name = item.Element("name").Value.ToString(); ObjPizzaItem.Cost = item.Element("cost").Value.ToString(); ObjPizzaItem.Description = item.Element("description").Value.ToString(); ObjPizzaList.Add(ObjPizzaItem);
Try removing the Frame and addition decorations and start with a basic LV
You do not need the grid R/C in the listview ;P Ah think I have got it - your List should be an ObservableCollection<>.
Never underestimate the power of human stupidity - RAH I'm old. I know stuff - JSOP
-
Try removing the Frame and addition decorations and start with a basic LV
You do not need the grid R/C in the listview ;P Ah think I have got it - your List should be an ObservableCollection<>.
Never underestimate the power of human stupidity - RAH I'm old. I know stuff - JSOP
I have it working. Yes ObservableCollections are the way to go but generic Lists are fine as well. The problem is that when the Model is bound the WebService call has not completed so when the List property is bound it is still null. Even when updated at this point the ObservableCollection won't work because it has not been seeded. The solution is to seed the ObservableCollection, or List, on the Page's OnAppearing event and bind the ViewModel as the BindingContext in this event. My solution is below:
protected override async void OnAppearing() { var vm = new ViewModel.ViewModel(); if (vm == null) return; HttpClient client = new HttpClient(); HttpResponseMessage responseGet = await client.GetAsync(vm.Geturi); string response = await responseGet.Content.ReadAsStringAsync(); //Xml Parsing var \_objPizzaList = new ObservableCollection(); XDocument doc = XDocument.Parse(response); vm.GetRequest(doc); this.BindingContext = vm; }