Updating ObservableCollection does not properly update ListView in Xamarin Forms

I have a ListView in XAML that is bound to an ObservableCollection in the ViewModel. Upon initialization or OnAppearing() the ListView items are displayed perfectly.

However, when I try to update the ListView items from within the page (through ViewModel) the items are updated but the old items are still there.

Basically, the new items are added to the ListView but below the items that were in the ObservableCollection before. I have implemented INotifyPropertyChanged and I think I have done everything correct (although clearly not).

Please tell me what I'm doing wrong. I've tried Clear() on the Collection but to no avail (same outcome).

BaseViewModel:

public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingField, value))
                return;

            backingField = value;

            OnPropertyChanged(propertyName);
        }
}

XAML:

<ListView       IsEnabled="{Binding IsLoadingTable, Converter={Helpers:InverseBoolConverter}}"
                        IsVisible="{Binding IsLoadingTable, Converter={Helpers:InverseBoolConverter}}"
                        ItemsSource="{Binding LeagueStandings}"
                        SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
                        ItemSelected="ListView_ItemSelected"
                        RowHeight="60"
                        SeparatorVisibility="Default"
                        SeparatorColor="{DynamicResource accentColor}">

Page.cs:

protected override void OnAppearing()
        {
            base.OnAppearing();

            ViewModel.LoadLeagueStandingsCommand.Execute(_divisionId);
            ViewModel.LoadPickerItemsCommand.Execute(null);
        }

ViewModel Initialization:

private ObservableCollection<Standing> _leagueStandings;
        public ObservableCollection<Standing> LeagueStandings
        {
            get { return _leagueStandings ?? (_leagueStandings = new ObservableCollection<Standing>()); }
            set { OnPropertyChanged(nameof(LeagueStandings)); }
        }

ViewModel Methods:

private async Task LoadLeagueStandings(string divId)
        {

            if (_hasLoadedStandings)
                return;

            if (IsLoadingTable)
                return;

            _hasLoadedStandings = true;

            _divisionId = divId;

            try
            {
                IsLoadingTable = true;
                await _pageService.DisplayAlert("loading Selected", _divisionId, "ok");
                var v = await GetLeagueTableAsync(_htmlParser, _divisionId);

                LeagueStandings = new ObservableCollection<Standing>(v);

            }
            catch (Exception)
            {
                System.Diagnostics.Debug.WriteLine("Exception caught in DivisionsViewModel.cs.(LoadLeagueStandings).");
            }
            finally
            {
                IsLoadingTable = false;
            }

        }

ViewModel method called when Picker item changes:

private async Task SelectItem(string item)
        {
            if (item == null)
                return;

            SelectedItem = null;

            var id = await _divisionFinder.GetDivisionIdAsync(item);

            var v = await GetLeagueTableAsync(_htmlParser, id);

            LeagueStandings = new ObservableCollection<Standing>(v);
        }

Answers

  • AlessandroCaliaroAlessandroCaliaro ✭✭✭✭✭ ITMember ✭✭✭✭✭

    I don't use code like

    LeagueStandings = new ObservableCollection<Standing>(v);
    

    I add Items to a ObservableCollection with a foreach, and use Clear or Remove to remove items. I don't know if it can be useful for you

  • voidstreamvoidstream ✭✭✭ FRMember ✭✭✭
    edited March 2018

    @vilothbrok

    List<> does not refresh a view if you use Add/Remove. We have to say that List<> is equal to a new list. On the other hand ObservableCollection makes it possible to resolve this problem by refreshing well the view!

  • JuanuJuanu ✭✭ USMember ✭✭

    I'm currently experiencing a similar behaviour.
    I have a LIstView on the last page of my carousel.
    On the OnAppearing Method, the items update with the correct information but on the View, nothing gets updated.
    I know that the NOtifyPropertyChanged event is being raised, so that's not the issue.

  • RadoslawKubasRadoslawKubas ✭✭ USMember ✭✭
    edited August 23

    There is something strange in this code:

    public ObservableCollection<Standing> LeagueStandings
            {
                get { return _leagueStandings ?? (_leagueStandings = new ObservableCollection<Standing>()); }
                set { OnPropertyChanged(nameof(LeagueStandings)); }
            }
    

    LeagueStandings = new ObservableCollection<Standing>(v);

    since set is just "OnPropertyChanged(nameof(LeagueStandings));" I think it is not working correctly.

    seems it suppose to be:

    public ObservableCollection<Standing> LeagueStandings
            {
                get { return _leagueStandings ?? (_leagueStandings = new ObservableCollection<Standing>()); }
                set { SetValue(ref _leagueStandings, value); }
            }
    
Sign In or Register to comment.