ItemsSource更改时选择器未更新

时间:2018-10-13 19:10:29

标签: xamarin.forms observablecollection

我有一个Xamarin.Forms(3.2,最新版本)Picker,其实现为

<Picker x:Name="ClassSelector"
            Title="Select Class"
            ItemsSource="{Binding Classrooms}"
            ItemDisplayBinding="{Binding ClassroomName}"
            SelectedItem="{Binding SelectedClassroom}">
</Picker>

BindingContext是此ViewModel:

public class ClassroomsViewModel : BaseViewModel
{
  public ObservableCollection<Classroom> Classrooms { get; set; }

  public ClassroomsViewModel()
  {
     Classrooms = new ObservableCollection<Classroom>(_ClassroomsRepository.GetAll());
  }
}

现在,当我在ViewModel中添加教室时,Picker会忠实地将该项目添加到其列表中:

 Classrooms.Add(new Classroom() { ClassroomName = "test" });   // this works fine

但是,如果我修改一间教室,Picker不会更新其项目列表:

Classrooms[0].ClassroomName = "test";  // this doesn't have an effect,
                                       // although the value is set
                                       // in the ObservableCollection

我也尝试过显式调用:

    OnPropertyChanged();  // nothing
    OnPropertyChanged("Classrooms"); // nope

如果重要的话,Classroom确实来自ObservableObject

public class Classroom : ObservableObject
{
   private string classroomName;

   public string ClassroomName { get => classroomName; set => SetProperty(ref classroomName, value); }
}

编辑,我在其中澄清了这个不是回收问题:

请注意,我不是用新的ObservableCollection替换Classrooms集合,就像其他帖子中出现的那样,类似于我的问题。我只是修改该收藏集的成员之一。当此集合绑定到其他控件(如ListView)时,它的行为与预期的完全一样-ListView更新以反映新的ClassroomName

有人可以指出我在做什么吗?

2 个答案:

答案 0 :(得分:2)

通常,当我们使用绑定时,我们希望目标(一个选择器项)与绑定源(在这种情况下为Classroom对象)保持同步-因此,您的代码在设计上会是正确的。

但是,在XF github中探究了Picker源代码之后-从Binding提取第一个值后,它似乎取消了对绑定/属性更改的预订。 Here you can see the explicit call to UnApply()到绑定,然后到picker-item显示名称的binding-expression。

OnPropertyChanged("Classrooms");上调用CustomerViewModel(而不是在Customer上调用)在技术上应该可行。或者,您可以尝试从集合中删除修改后的Customer对象,然后重新添加相同的索引来解决此问题。这两个操作都将触发ResetItems()-反过来又应触发picker-item's display name的刷新。

答案 1 :(得分:0)

出于某种原因,将源设置为空然后重置它对我有用:

var items = picker.ItemsSource as List<string>;
items.Add("item");
picker.ItemsSource = null;
picker.ItemsSource = items;