更新 ObservableCollection 无法正确更新 Xamarin 表单中的 ListView
Posted
技术标签:
【中文标题】更新 ObservableCollection 无法正确更新 Xamarin 表单中的 ListView【英文标题】:Updating ObservableCollection does not properly update ListView in Xamarin Forms 【发布时间】: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.LeagueStandingsdivisionId";
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】:由于您既没有添加也没有删除项目,并且您正在替换引用,您需要引发事件来告知视图已更改。而不是你的代码,用这个替换它
private ObservableCollection<Standing> _leagueStandings;
public ObservableCollection<Standing> LeagueStandings
get return _leagueStandings;
set
_leagueStandings = value;
RaisePropertyChanged("LeagueStandings");
为了将来的参考,ObservableCollection
已经实现了INotifyPropertyChanged
,所以你不需要SetValue(x)
..
【讨论】:
我已经完成了上述操作,但仍然得到相同的结果。private ObservableCollection<Standing> _leagueStandings; public ObservableCollection<Standing> LeagueStandings get return _leagueStandings; set _leagueStandings = value; OnPropertyChanged("LeagueStandings");
我将编辑帖子以显示结果
你能不能尝试在ObservableCollection<Standing> temp = new ObservableCollection<Standing>(v); LeagueStandings = temp;
中破解它
好的,我刚刚完成了这个。在断点处,LeagueStandings 的计数是 8(正确),临时计数是 13(应该是 5)所以看起来问题可能不在于 observablecollection 而是我的异步调用? Temp 的计数应该是 5,但似乎是 8(先前计数)+ 5(新计数)。有什么想法吗??
GetLeagueTableAsync
可能和这条线有关.. 不知道你在里面做什么
我已将该方法添加到我的帖子中。如果你有第二个,请帮帮我!感谢您的努力!以上是关于更新 ObservableCollection 无法正确更新 Xamarin 表单中的 ListView的主要内容,如果未能解决你的问题,请参考以下文章
如何通过工作线程更新 ObservableCollection?
如何根据 WPF DataGrid 中的更改更新 ObservableCollection 项属性?
ObservableCollection 不更新 ListView (WPF) [重复]