更新 ObservableCollection 不会正确更新 Xamarin Forms 中的 ListView

Updating ObservableCollection does not properly update ListView in Xamarin Forms

我在 XAML 中有一个 ListView,它绑定到 ViewModel 中的一个 ObservableCollection。在初始化或 OnAppearing() 时,ListView 项目完美显示。

但是,当我尝试从页面内(通过 ViewModel)更新 ListView 项目时,项目已更新,但旧项目仍然存在。

基本上,新项目被添加到 ListView 但低于之前 ObservableCollection 中的项目。我已经实施了 INotifyPropertyChanged,我认为我做的一切都是正确的(虽然显然不是)。

请告诉我哪里做错了。我已经在 Collection 上尝试了 Clear() 但无济于事(相同的结果)。

基础视图模型:

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 初始化:

private ObservableCollection<Standing> _leagueStandings;
        public ObservableCollection<Standing> LeagueStandings
        {
            get { return _leagueStandings ?? (_leagueStandings = new ObservableCollection<Standing>()); }
            set { SetValue(ref _leagueStandings, value); }
        }

ViewModel 方法:

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 方法:

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

编辑* - 结果图片。第一个集合以数字 5 结束,新集合再次从 1 开始追加到列表视图的末尾。

ListView Image

编辑 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;

由于您既没有添加也没有删除项目,并且您正在替换引用,因此您需要引发事件以告知视图已更改。用这个

替换你的代码,而不是你的代码
    private ObservableCollection<Standing> _leagueStandings;
    public ObservableCollection<Standing> LeagueStandings
    {
        get { return _leagueStandings; }
        set { 
              _leagueStandings = value;
              RaisePropertyChanged("LeagueStandings"); 
            }
    }

此外,ObservableCollection 已经实施了 INotifyPropertyChanged,因此您不需要 SetValue(x)..