user3355961
user3355961

Reputation: 725

Populate Picker with Data using MVVM Xamarin Forms

I am trying to get a picker to populate with data. There doesn't seem to be a straight answer anywhere on this. I have tried numerous things, one thing that does work is :

Xaml:

<Picker Grid.Row="2"
           Grid.Column="0"
           Grid.ColumnSpan="4"
           Title="Driver Name"
            ItemsSource="{Binding Drivers}"                
            SelectedItem="{Binding driverID}"

and in the View Model:

List<string> Drivers = new List<string> { "Steve","Dave" };

This works fine, but its just a dummy capability as in the future these names will be grabbed from a service of some kind. So in an attempt to copy this I tried separating this list into a mock service and just returning the list to the view model and making it work that way.

But this still returns nothing to the front end even though I can see that the list is not blank when debugging. Then I tried to create a class of Driver and return instances of the class that has the name in it and access it in the Xaml. This did not work, I even tried a variation using IList, this did not work either.

I am not sure why this does not work as the list was just separated to essentially a different class. For instance this is what I am trying now:

Xaml:

 <Picker Grid.Row="2"
           Grid.Column="0"
           Grid.ColumnSpan="4"
           Title="Driver Name"
            ItemsSource="{Binding Drivers}"                
            SelectedItem="{Binding driverID}"
            />

View Model:

This is bound to the picker

public List<string> Drivers;

Then this method is called from the constructor:

 public async Task FindDriverNames()
    {
        Drivers = await GetDriverNames();           
    }

and in the Model:

 public async Task<List<string>> GetDriverNames()
        {
            await Sleep();

            List<string> _drivers = new List<string> { "Steve"};

            return _drivers;          

        }

This does not work, but when run through debug it shows that Drivers is populated. I have wasted a lot of time trying to get this work, does anyone have insights?

Upvotes: 3

Views: 4129

Answers (1)

Stefan
Stefan

Reputation: 17678

You'll need an ObservableCollection, and possibly a INotifyPropertyChanged interface implementation to notify the view for any changes.

public class YourViewModel: INotifyPropertyChanged
{
     public YourViewModel()
     { 
         Drivers = new ObservableCollection<string>();
     }

     private ObservableCollection<string> _drivers;
     public ObservableCollection<string> Drivers
     {
         get { return _drivers; }
         set
         {
            if (Equals(value, _drivers)) return;
            _drivers= value;
            OnPropertyChanged(nameof(Drivers));
         }
     }

     protected virtual void OnPropertyChanged(string propertyName)
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
     }
}

By implementing the INotifyPropertyChanged interface, you will allow the view to be updated whenever the whole list changes. The observable collection will notify the UI if a item is added to the collection.

As noted by Roman, youo can also, in this specific case use the observable collection to update the ui.

public async Task FindDriverNames()
{
    Drivers.Clear();
    Drivers.AddRange(await GetDriverNames());           
}

For other bound properties you'll still need the OnPropertyChanged event.

See ObservableCollection<T> and INotifyPropertyChanged

Upvotes: 2

Related Questions