Android应用中ObservableCollection数据无法显示在CollectionView的问题
CollectionView添加车辆后无法自动更新列表的问题解决
我测试一款Android端移动应用时,遇到了数据从ViewModel传递到UI的CollectionView的问题——主菜单显示车辆列表,但添加车辆后,列表无法自动更新。
之前按要求定义了两个ObservableCollection:
ObservableCollection<AutoWithSwitch> MyList = new ObservableCollection<AutoWithSwitch>(); public ObservableCollection<AutoWithSwitch> AutoData { get { return MyList; } set { MyList = value; } }
填充MyList后赋值给CollectionView的ItemSource(AutoData)的逻辑在其他场景正常,但添加车辆后失效。以下是关键代码:
EnterCarViewModel中添加车辆的代码
int results = await repository.AddAutoData(data); if (results == 1) { IsVisibleResults = true; EntResults = "Entered Successfully"; if (Convert.ToBoolean(Preferences.Default.Get("firstAutoEntered", false))) { Preferences.Set("autoId", 1); Preferences.Set("firstAutoEntered", false); } Preferences.Set("CarAdded", true); mmvm.GetMyCars(await repository.GetAuto()); await Shell.Current.GoToAsync("///MainPage"); }
MainMenuViewModel中的GetMyCars方法
public async void GetMyCars(List<AutoTableDefination> atd) { try { bool processed = false; MileageItemRepository repo = new MileageItemRepository(); MyList = new ObservableCollection<AutoWithSwitch>(); AutoData = new ObservableCollection<AutoWithSwitch>(); var autoId = Convert.ToInt32(Preferences.Get("autoId", 0)); if (atd.Count > 0) { foreach (var item in atd) { if (item.CarDesc.ToUpper() == Preferences.Default.Get("UpperCar", string.Empty)) { if (item.Id == autoId) { item.CarDesc = item.CarDesc.ToUpper(); Preferences.Default.Set("UpperCar", item.CarDesc.ToUpper()); Preferences.Default.Set("autoId", item.Id); } } if (item.IsDefault) item.CarDesc = "**" + item.CarDesc; if (item.IsDefault && !processed) { Preferences.Default.Set("autoId", item.Id); } Preferences.Default.Set("enter1stCar", false); if (!processed) { processed = false; } MyList.Add(new AutoWithSwitch { Id = item.Id, Name = item.CarDesc }); } var sortedList = MyList.OrderBy(x => x.Name); MyList = new ObservableCollection<AutoWithSwitch>(sortedList); AutoData = MyList; MainPage mainPage = new MainPage(AutoData, cv); //cv.ItemsSource = null; //cv.ItemsSource = AutoData; processed = true; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } if (Convert.ToBoolean(Preferences.Get("CarAdded", true))) Device.BeginInvokeOnMainThread(async () => { await App.Current.MainPage.DisplayAlert("Success", "Car successfully added", "Ok"); }); }
尝试过直接设置ItemsSource、通过MainPage构造函数传递数据两种方式,均无效,寻求解决方案。
问题根源
- AutoData未实现属性变更通知:直接赋值新的ObservableCollection时,UI无法感知属性变化,因为没有触发
PropertyChanged事件。 - 重复实例化集合破坏绑定:每次调用
GetMyCars都新建集合实例,原UI绑定的是旧实例,新数据无法同步。 - 错误创建新页面实例:
MainPage mainPage = new MainPage(AutoData, cv);生成了未显示的新页面,当前展示的旧页面不会更新。
修复步骤
1. 让ViewModel实现INotifyPropertyChanged
确保MainMenuViewModel实现属性变更通知接口,让UI感知属性变化:
public class MainMenuViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private ObservableCollection<AutoWithSwitch> _myList = new ObservableCollection<AutoWithSwitch>(); public ObservableCollection<AutoWithSwitch> AutoData { get { return _myList; } set { _myList = value; OnPropertyChanged(); // 触发属性变更通知 } } }
2. 复用集合实例,避免重新创建
清空现有集合再添加新数据,保持绑定的集合实例不变,UI会自动感知内容变化:
public async void GetMyCars(List<AutoTableDefination> atd) { try { bool processed = false; MileageItemRepository repo = new MileageItemRepository(); var autoId = Convert.ToInt32(Preferences.Get("autoId", 0)); if (atd.Count > 0) { // 清空现有集合,而非重新实例化 Device.BeginInvokeOnMainThread(() => AutoData.Clear()); var tempList = new List<AutoWithSwitch>(); foreach (var item in atd) { if (item.CarDesc.ToUpper() == Preferences.Default.Get("UpperCar", string.Empty)) { if (item.Id == autoId) { item.CarDesc = item.CarDesc.ToUpper(); Preferences.Default.Set("UpperCar", item.CarDesc.ToUpper()); Preferences.Default.Set("autoId", item.Id); } } if (item.IsDefault) item.CarDesc = "**" + item.CarDesc; if (item.IsDefault && !processed) { Preferences.Default.Set("autoId", item.Id); } Preferences.Default.Set("enter1stCar", false); if (!processed) { processed = false; } tempList.Add(new AutoWithSwitch { Id = item.Id, Name = item.CarDesc }); } // 排序后在UI线程添加到集合 var sortedList = tempList.OrderBy(x => x.Name); Device.BeginInvokeOnMainThread(() => { foreach (var auto in sortedList) { AutoData.Add(auto); } }); processed = true; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } if (Convert.ToBoolean(Preferences.Get("CarAdded", true))) Device.BeginInvokeOnMainThread(async () => { await App.Current.MainPage.DisplayAlert("Success", "Car successfully added", "Ok"); }); }
3. 移除多余的页面实例创建
删除MainPage mainPage = new MainPage(AutoData, cv);代码,当前显示的MainPage已绑定集合,更新集合内容即可同步UI。
内容的提问来源于stack exchange,提问作者Steve H
相关产品推荐
相关产品推荐

