locked
Listview Binding not working RRS feed

  • Question

  • User261681 posted

    I have the following in pcl

    <Label Text="Hello, XAML!"
            VerticalOptions="Start"
            HorizontalTextAlignment="Center"
            Rotation="-15"
            IsVisible="true"
            FontSize="Large"
            FontAttributes="Bold"
            TextColor="Aqua" />
    
    <ListView ItemsSource="{Binding EmployeeList}"
            HasUnevenRows="True">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <StackLayout Orientation="Vertical" Padding="12,6">
              <Label Text="{Binding Name}" />
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
    

    And the code behind:

        public partial class LoginPage : ContentPage
            {
                public LoginPage()
                {
                    InitializeComponent();
                    BindingContext = new LoginViewModel(this);
                }
    
                protected override void OnAppearing()
                {
                    base.OnAppearing();
                    LoginViewModel model = new LoginViewModel(this);
                    model.GetEmployees();
                }
            }
    

    And my viewmodel:

    public class LoginViewModel : INotifyPropertyChanged
        {
            LoginPage page;
            private List<Employees> _employeeList;
    
            public List<Employees> EmployeeList
            {
                get { return _employeeList; }
                set
                {
                    _employeeList = value;
                    OnPropertyChanged();
                }
            }
    
            public LoginViewModel(LoginPage parent)
            {
                page = parent;
            }
    
            public async void GetEmployees()
            {
                var loginService = new LoginService();
                EmployeeList = await loginService.GetEmployeesAsync();
            }
    
            public Command GetListCommand //TODO: CHANGE ME
            {
                get
                {
                    return new Command(async () =>
                    {
                        var loginService = new LoginService();//should proc going to new page, stock for now
                        EmployeeList = await loginService.GetEmployeesAsync();
                    });
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
            }
        }
    

    Issue I have although my service is returning 427 results, and my employees list is populated with 1 property called "Name". its always blank when rendering. Have i missed something?

    Thursday, December 8, 2016 2:22 PM

Answers

  • User261681 posted

    Turns out it has nothing to to do with observable collections, this threw me as i have a demo that uses lists and onproperty notification without ever using collection notfication.

    The change that made this work:

    protected override void OnAppearing()
            {
                base.OnAppearing();
                LoginViewModel model = new LoginViewModel(this);
                model.GetEmployees();
                BindingContext = model;
            }
    

    If any one has noticed the last line solved the issue, I think its how im calling my viewmodel, I feel im doing this wrong, but this is more a quick fix by rebinding it to a new instance of viewmodel that has the property list set.

    I expect a better solution would be some sort of DI? or possibly message service?

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, December 9, 2016 10:21 AM

All replies

  • User180523 posted

    Same problem as here: https://forums.xamarin.com/discussion/comment/238729/#Comment_238729

    Thursday, December 8, 2016 2:39 PM
  • User261681 posted

    So using INotifyCollectionChanged and implimenting, OnCollectionChanged method on the invoke what NotifyCollectionChangedAction should i be using?

    protected virtual void OnCollectionChanged( NotifyCollectionChangedAction action)
            {
                CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(action));
            }
    

    Is what i have set up, threw a breakpoint here but only my propertychanged is hit not the collection. Am i on the correct path or did i miss something?

    Thursday, December 8, 2016 2:47 PM
  • User60022 posted

    List doesn't implement INotifyChanged so it never fires, you need an ObservableCollection

    This stackoverflow answer is what you are looking for http://stackoverflow.com/a/8470177/4314198

    Thursday, December 8, 2016 3:59 PM
  • User265422 posted

    I use binding listview without INotifyChanged and ObservableCollection.

    Your XAML is okay I just put in the code behind, MyListView.ItemsSource = MyListOfObjects(); :/ You do that for the refresh of list?

    Thursday, December 8, 2016 4:34 PM
  • User261681 posted

    @MikeRowley403 said: List doesn't implement INotifyChanged so it never fires, you need an ObservableCollection

    This stackoverflow answer is what you are looking for http://stackoverflow.com/a/8470177/4314198

    I changed my list to Observable collection, changed this throughout my code, still nothing, the only things thats ever called is the OnPropertyChanged method, which is correct as the employeelist property is being changed with the values i get back for my web api.

    The issue however is my list on my front end is still showing blank.

    EDIT: just realized i forgot to call my new method for collections. by the way my new method is:

     protected virtual void OnCollectionChanged( NotifyCollectionChangedAction action)
            {
                CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(action));
            }
    

    And i now call it like,

    public ObservableCollection<Employees> EmployeeList
        {
            get { return _employeeList; }
            set
            {
                _employeeList = value;
                OnPropertyChanged();
                OnCollectionChanged(NotifyCollectionChangedAction.Reset);
            }
        }
    

    Just stepped through and CollectionChanged is null so if im correct the Invoke never happens for the notify.
    Any reason why this would see it as null? what am i missing?

    I take it my OnAppearing method is ok on the xaml code behind?

    Friday, December 9, 2016 8:35 AM
  • User261681 posted

    Turns out it has nothing to to do with observable collections, this threw me as i have a demo that uses lists and onproperty notification without ever using collection notfication.

    The change that made this work:

    protected override void OnAppearing()
            {
                base.OnAppearing();
                LoginViewModel model = new LoginViewModel(this);
                model.GetEmployees();
                BindingContext = model;
            }
    

    If any one has noticed the last line solved the issue, I think its how im calling my viewmodel, I feel im doing this wrong, but this is more a quick fix by rebinding it to a new instance of viewmodel that has the property list set.

    I expect a better solution would be some sort of DI? or possibly message service?

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, December 9, 2016 10:21 AM
  • User60022 posted

    @StevenSmith.6830 CollectionChanged is an event and will be null unless something is attached to that event, hence your null propagation to avoid a NullReferenceException when using it. As this is obviously an incomplete code set its almost impossible to say exactly what is wrong but this may push you in the correct direction. http://stackoverflow.com/questions/4588359/implementing-collectionchanged

    I think your biggest issue is that you are doing all of the heavy lifting unnecessarily, is there a reason why you aren't using an MVVM framework? Personally I use MVVM Light http://www.mvvmlight.net/ but MVVMCross is also very popular https://github.com/MvvmCross. With MVVM Light you simply call RaisePropertyChanged(() => EmployeeList); and it triggers the iNotify events automatically.

    An MVVM Framework would take care of much of the heavy lifting for you and I suspect it would simplify the process for you and likely solve your issue.

    The last gotcha I have run into often with ListView's being empty, is that the data actually loads but the bindings are wrong so the ViewCells are simply empty. Just something to be aware of.

    Friday, December 9, 2016 5:59 PM