Updating ObservableCollection does not properly update ListView in Xamarin Forms

亡梦爱人 提交于 2020-01-06 08:17:06

问题


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 { SetValue(ref _leagueStandings, value); }
        }

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);
        }

Edit* - Picture of outcome. First collection ends at number 5 and new collections appends to end of listview starting at 1 again.

ListView Image

Edit 2:

public async Task<IEnumerable<Standing>> GetLeagueTableAsync(string divisionId)
    {
        // todo: get division Id from picker

        string address = "";
        if (IsOnline)
        {
            if (divisionId != "")
                address = $"{BaseUrls.LeagueStandings}{divisionId}";

            try
            {
                var config = Configuration.Default.WithDefaultLoader();
                var document = await BrowsingContext.New(config).OpenAsync(address);
                var cSelector = "table[class='table table-striped table-hover table-bordered'] tr";

                var table = document.QuerySelectorAll(cSelector).Skip(1);

                int count = 0;
                foreach (var c in table)
                {
                    var cells = c.QuerySelectorAll("td").ToArray();

                    _leagueStandings.Add(new Standing(++count, cells[0].TextContent.Trim(), cells[1].TextContent.Trim(),
                                                               cells[2].TextContent.Trim(), cells[3].TextContent.Trim(),
                                                               cells[4].TextContent.Trim(), cells[5].TextContent.Trim(),
                                                               cells[6].TextContent.Trim(), cells[7].TextContent.Trim()));
                }
            }
            catch(Exception e)
            {
                System.Diagnostics.Debug.WriteLine($"\n\n Exception caught LoadingLeagueTable - {e} \n\n");
            }
        }
        return _leagueStandings;

回答1:


Since you're not adding neither removing items, and you're replacing the reference you need to raise the event telling that the view has changed. Instead of your code, replace it by this

    private ObservableCollection<Standing> _leagueStandings;
    public ObservableCollection<Standing> LeagueStandings
    {
        get { return _leagueStandings; }
        set { 
              _leagueStandings = value;
              RaisePropertyChanged("LeagueStandings"); 
            }
    }

Also for future references, ObservableCollection already implements INotifyPropertyChanged so you don't need to SetValue(x)..



来源:https://stackoverflow.com/questions/49137114/updating-observablecollection-does-not-properly-update-listview-in-xamarin-forms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!