【问题标题】:Updating ObservableCollection does not properly update ListView in Xamarin Forms更新 ObservableCollection 无法正确更新 Xamarin 表单中的 ListView
【发布时间】:2018-08-14 16:21:29
【问题描述】:

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

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

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

请告诉我我做错了什么。我在 Collection 上尝试过 Clear() 但无济于事(结果相同)。

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

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

        }

Picker 项目更改时调用的 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;

【问题讨论】:

    标签: c# listview xamarin xamarin.forms observablecollection


    【解决方案1】:

    由于您既没有添加也没有删除项目,并且您正在替换引用,您需要引发事件来告知视图已更改。而不是你的代码,用这个替换它

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

    为了将来的参考,ObservableCollection 已经实现了INotifyPropertyChanged,所以你不需要SetValue(x)..

    【讨论】:

    • 我已经完成了上述操作,但仍然得到相同的结果。 private ObservableCollection&lt;Standing&gt; _leagueStandings; public ObservableCollection&lt;Standing&gt; LeagueStandings { get { return _leagueStandings; } set { _leagueStandings = value; OnPropertyChanged("LeagueStandings"); } }我将编辑帖子以显示结果
    • 你能不能尝试在ObservableCollection&lt;Standing&gt; temp = new ObservableCollection&lt;Standing&gt;(v); LeagueStandings = temp;中破解它
    • 好的,我刚刚完成了这个。在断点处,LeagueStandings 的计数是 8(正确),临时计数是 13(应该是 5)所以看起来问题可能不在于 observablecollection 而是我的异步调用? Temp 的计数应该是 5,但似乎是 8(先前计数)+ 5(新计数)。有什么想法吗??
    • GetLeagueTableAsync 可能和这条线有关.. 不知道你在里面做什么
    • 我已将该方法添加到我的帖子中。如果你有第二个,请帮帮我!感谢您的努力!
    猜你喜欢
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2020-06-12
    相关资源
    最近更新 更多