如何将ListView下Picker的SelectedItem值存入数组?(Xamarin)
问题分析与解决方案
问题根源
你遇到的核心问题是:每个GPADetails实例的SelectedUnit属性在赋值时,没有操作同一个共享的数组实例,反而可能每次都重新创建数组,或者每个实例持有独立的数组引用,导致之前的索引值被覆盖为null。
解决方案1:通过委托实现数据同步(解耦推荐)
这种方式让GPADetails无需直接持有数组引用,通过委托将选中值传递给ViewModel统一维护数组,更符合MVVM解耦原则。
1. 调整GPADetails类
添加一个委托属性,用于通知外部更新数组:
public class GPADetails : INotifyPropertyChanged { private string _selectedUnit; public int TemplateID { get; set; } public ObservableRangeCollection<string> UnitList { get; set; } // 委托:传递TemplateID和选中值给外部处理 public Action<int, string> OnSelectedUnitChanged { get; set; } public string SelectedUnit { get => _selectedUnit; set { if (_selectedUnit != value) { _selectedUnit = value; OnPropertyChanged(nameof(SelectedUnit)); // 触发委托,同步更新数组 OnSelectedUnitChanged?.Invoke(TemplateID, value); } } } // INotifyPropertyChanged实现 public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 在ViewModel中维护共享数组并绑定委托
ViewModel初始化时创建全局数组,并为每个GPADetails实例绑定委托:
public class GPAViewModel : INotifyPropertyChanged { private string[] _selectedUnitsArray; public ObservableRangeCollection<GPADetails> GPADetailsList { get; set; } public GPAViewModel(int courseCount) { // 初始化数组,长度与课程数量一致 _selectedUnitsArray = new string[courseCount]; GPADetailsList = new ObservableRangeCollection<GPADetails>(); // 生成对应数量的课程项 for (int i = 0; i < courseCount; i++) { var gpaItem = new GPADetails { TemplateID = i, UnitList = new ObservableRangeCollection<string> { "A", "B", "C", "D", "F" }, // 绑定委托:更新共享数组 OnSelectedUnitChanged = (id, value) => { if (id >= 0 && id < _selectedUnitsArray.Length) _selectedUnitsArray[id] = value; } }; GPADetailsList.Add(gpaItem); } } // INotifyPropertyChanged实现省略 }
解决方案2:通过事件监听实现数据同步
如果不想用委托,也可以在ViewModel中监听每个GPADetails实例的PropertyChanged事件,主动更新数组:
ViewModel代码调整
public GPAViewModel(int courseCount) { _selectedUnitsArray = new string[courseCount]; GPADetailsList = new ObservableRangeCollection<GPADetails>(); for (int i = 0; i < courseCount; i++) { var gpaItem = new GPADetails { TemplateID = i, UnitList = new ObservableRangeCollection<string> { "A", "B", "C", "D", "F" } }; // 监听每个项的属性变化事件 gpaItem.PropertyChanged += GpaItem_PropertyChanged; GPADetailsList.Add(gpaItem); } } private void GpaItem_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(GPADetails.SelectedUnit)) { var item = sender as GPADetails; if (item != null && item.TemplateID >= 0 && item.TemplateID < _selectedUnitsArray.Length) { _selectedUnitsArray[item.TemplateID] = item.SelectedUnit; } } }
关键注意事项
- 必须使用共享数组实例:确保所有
GPADetails实例操作的是同一个数组,而非各自创建新数组。 - 索引边界检查:更新数组时要判断
TemplateID是否在数组索引范围内,避免越界异常。 - MVVM原则:尽量让
GPADetails只负责自身属性维护,数据收集逻辑交给ViewModel处理,降低耦合。
内容的提问来源于stack exchange,提问作者Samuel Mbah
相关产品推荐
相关产品推荐

