Graham Charles
Graham Charles

Reputation: 9632

Picker not updating when ItemsSource changed

I have a Xamarin.Forms (3.2, latest version) Picker implemented as

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

The BindingContext is this ViewModel:

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

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

Now, when I add a classroom in the ViewModel, the Picker dutifully adds the item to its list:

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

But if I modify a classroom, the Picker doesn't update its items list:

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

I've also tried explicitly calling:

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

If it's important, Classroom does derive from ObservableObject:

public class Classroom : ObservableObject
{
   private string classroomName;

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

Edit, in which I clarify that this isn't a collection-replacement issue:

Note that I am not replacing the Classrooms collection with a new ObservableCollection -- as happens in other posts that may appear similar to my issue. I am simply modifying one of the collection's members. When this collection is bound to a different control (like a ListView), it behaves exactly as expected -- the ListView updates to reflect the new ClassroomName.

Can anyone point me to what I'm doing wrong?

Upvotes: 7

Views: 5365

Answers (2)

Savage
Savage

Reputation: 2349

For some reason, setting the source to null and then resetting it works for me:

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

Upvotes: 2

Sharada
Sharada

Reputation: 13601

Typically, when we use bindings, we expect the target (a picker-item) to keep itself in sync with the binding source (in this case a Classroom object) - so, your code, by design, is correct.

However, after digging into Picker source code in XF github - it looks like it unsubscribes from binding/property-changes after pulling the first value from Binding. Here you can see the explicit call to UnApply() to the binding, and subsequently to the binding-expression for picker-item display name.

Invoking OnPropertyChanged("Classrooms"); on CustomerViewModel (not on Customer) should technically work. Or, you can try removing the modified Customer object from the collection, and re-adding at same index to fix this issue. Both of these actions will trigger the ResetItems() - which in turn should trigger the refresh for picker-item's display name.

Upvotes: 6

Related Questions