Apologies if the answer is obvious as I am brand new to mobile/xamarin dev. I am implementing a simple Employee Directory app and have hit a snag. I have my view which is a content page and my viewmodel for binding. In this view is an ActivityIndicator that shows while the data loads by binding to the ViewModel's IsBusy Property and a ListView to display the data. I can successfully load the data asynchronously. However, I cannot get the data to the ItemsSource of the ListView after loading. Please take a look at my code below and see if you can spot what I'm missing. I'm sure there's a core concept I'm not grasping somewhere.
BaseViewModel.cs
public class BaseViewModel : INotifyPropertyChanged { private bool mblnIsBusy; public bool IsBusy { get { return mblnIsBusy; } set { mblnIsBusy = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if(handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } }
EmployeeListViewModel.cs
public class EmployeeListViewModel : BaseViewModel { public ObservableCollection<Employee> EmployeeList { get { return mcolEmployeeList; } set { mcolEmployeeList = value; OnPropertyChanged(); } } private ObservableCollection<Employee> mcolEmployeeList; public EmployeeListViewModel() { mcolEmployeeList = new ObservableCollection<Employee>(); } public void LoadEmployees() { string json = string.empty; EmployeeCollection colEmployees = JsonConvert.DeserializeObject<EmployeeCollection>(json); mcolEmployeeList = new ObservableCollection<Employee>(colEmployees.Employees); //left the above json empty to avoid pasting too much code (all the data retrieval) on this thread. I can confirm through debugging that this works //and the mcolEmployeeList gets a list of Employees } } }
EmployeeListView.cs
public class EmployeeDirectoryListView : BaseView { private ListView listView; private ToolbarItem toolbarItem; private EmployeeListViewModel ViewModel; private bool dataLoaded; public EmployeeDirectoryListView() { this.Title = "Contact List"; Icon = "Icon.png"; toolbarItem = new ToolbarItem("?", "Search.png", () => { var search = new SearchListView(); Navigation.PushAsync(search); }, 0, 0); ToolbarItems.Add(toolbarItem); ViewModel = new EmployeeListViewModel(); var activityIndicator = new ActivityIndicator { Color = Color.Black, BindingContext = ViewModel }; activityIndicator.SetBinding(ActivityIndicator.IsRunningProperty, "IsBusy"); activityIndicator.SetBinding(ActivityIndicator.IsEnabledProperty, "IsBusy"); activityIndicator.SetBinding(ActivityIndicator.IsVisibleProperty, "IsBusy"); listView = new ListView() { IsGroupingEnabled = true, GroupHeaderTemplate = new DataTemplate(typeof(GroupHeaderTemplate)), ItemTemplate = new DataTemplate(typeof(ListItemTemplate)), BindingContext = ViewModel, IsVisible = true }; listView.SetBinding(ListView.ItemsSourceProperty, "EmployeeList"); Content = new StackLayout() { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand, BackgroundColor = Color.White, Children = { activityIndicator, listView } }; } async protected override void OnAppearing() { if(!dataLoaded) { var complete = await LoadEmployees(); dataLoaded = true; } } private async Task<bool> LoadEmployees() { ViewModel.IsBusy = true; await Task.Delay(10000) .ContinueWith(task => ViewModel.LoadEmployees()); ViewModel.IsBusy = false; return true; } }
ListItemTemplate.cs
public class ListItemTemplate : ViewCell { public ListItemTemplate () { var nameLabel = new Label { VerticalTextAlignment = TextAlignment.Center, FontAttributes = FontAttributes.None, FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)), }; //PreferredName is a propert of object Employee nameLabel.SetBinding (Label.TextProperty, "PreferredName"); var titleLabel = new Label { VerticalTextAlignment = TextAlignment.Center, FontAttributes = FontAttributes.None, FontSize = Device.GetNamedSize (NamedSize.Micro, typeof(Label)), }; //Position is a propert of object Employee titleLabel.SetBinding (Label.TextProperty, "Position"); var information = new StackLayout { Padding = new Thickness (5, 0, 0, 0), VerticalOptions = LayoutOptions.StartAndExpand, Orientation = StackOrientation.Vertical, Children = { nameLabel, titleLabel } }; View = new StackLayout { Orientation = StackOrientation.Horizontal, Children = { information } }; } }
All pointers are greatly appreciated. Let me know if this needs clarification.
Just figured it out. In my LoadEmployees() method of EmployeeListViewModel I was setting the private field to the retrieved list of Employees instead of the public property. Therefore my OnPropertyChanged event was not firing. Nevermind
Answers
Just figured it out. In my LoadEmployees() method of EmployeeListViewModel I was setting the private field to the retrieved list of Employees instead of the public property. Therefore my OnPropertyChanged event was not firing. Nevermind