更新ObservableCollection不能正确更新Xamarin表单中的ListView [英] Updating ObservableCollection does not properly update ListView in Xamarin Forms

查看:117
本文介绍了更新ObservableCollection不能正确更新Xamarin表单中的ListView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

但是,当我尝试从页面内(通过ViewModel)更新ListView项时,这些项会更新,但旧项仍然存在.

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.

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

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).

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

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

BaseViewModel:

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

ViewModel Initialization:

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

ViewModel方法:

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

        }

当Picker项更改时调用的ViewModel方法:

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 *-结果的图片.第一个集合从5结束,新集合再次从1开始追加到listview的末尾.

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

ListView图片

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;

推荐答案

由于您既不添加删除项,也不替换引用,因此您需要引发事件以告知视图已更改.代替您的代码,用

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


ObservableCollection已经实现了INotifyPropertyChanged,以供将来参考,因此您无需SetValue(x).

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

这篇关于更新ObservableCollection不能正确更新Xamarin表单中的ListView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆