Picker within Listview

We needed to put a picker inside a list view in a Xamarin.Forms app, but we wanted to be notified when one of the pickers changed and be able to get the value from the picker (and know which one changed).

The complete source for this example is on GitHub.

My first impulse was to use EventToCommand, but that became a rabbit hole, and thanks to Lance and others on the Xamarin Community Forums, and email, I was redirected to a simpler approach that I will explain here.

We begin with a DataTemplate that we will use with our ListView.

<ContentPage.Resources>
    <DataTemplate x:Key="PickerTemplate">
        <ViewCell>
            <StackLayout HorizontalOptions="CenterAndExpand">
                <Label Text="Demo..."></Label>
                <Picker
                  HorizontalOptions="Center" 
                  ItemsSource="{Binding PickerList}"
                  SelectedItem =
"{Binding SelectedPickerItem, Mode=TwoWay}"
                  Title="My Picker"
                  FontSize="14">    
                </Picker>
            </StackLayout>
        </ViewCell>
    </DataTemplate>
</ContentPage.Resources>

Notice that there is a Picker and its ItemSource and SelectedItem are set. Also notice that the SelectedItem is two-way. All of this will be bound to the ViewModel by the code in the code-behind:

 public MainPage()
 {
     InitializeComponent();
     var vm = new MainPageViewModel();
     BindingContext = vm;
 }

The rest of the XAML is our ListView:

<ListView x:Name="DiscoveredItemsListView"
        HasUnevenRows="True"
        ItemTemplate="{StaticResource PickerTemplate}"
        ItemsSource="{Binding DiscoveredItemList}"
        SeparatorVisibility="None"
        VerticalOptions="StartAndExpand"
        Margin="5" >
</ListView>

OK, we have 4 bindings to examine: the Picker’s ItemsSource and SelectedItem, and the ListView’s ItemTemplate and ItemsSource.

The ListView’s ItemTemplate is easy, it is the ItemTemplate we just created above. Its ItemsSource is bound to “DiscoveredItemList” — let’s look at that.

public List<DiscoveredItem> DiscoveredItemList { get; set; }

Nothing surprising here but we do need to see what a DiscoveredItem is:

public class DiscoveredItem : ViewModelBase
{
    public int id { get; set; }

   public List<string> PickerList { get; set; }

   private string selectedPickerItem;
   public string SelectedPickerItem
   {
       get => selectedPickerItem;
       set => SetValue(ref selectedPickerItem, value); 
   }
}

Having it inherit from ViewModelBase is a quick hack… I happened to have it laying around and it takes care of the PropertyChangedNotification through the SetValue method.

Interestingly DiscoveredItem has a list of string named PickerList — we’ll come back to that. SelectedPickerItem is what the SelectedItem on our Picker binds to (see above).

The id is a quick and dirty way to know which DiscoveredItem was selected in the ListView. Let’s go look at the ViewModel where all the fun happens…

We saw that it has a List<DiscoveredItem> named DiscoveredItemList. It also has two private members:

private List<string> pickerItems;
private string firstPickerItem;

We’re going to initialize these in the constructor:

public MainPageViewModel()
{
    pickerItems = PopulateCollection();
    firstPickerItem = pickerItems.FirstOrDefault();

    PopulateDiscoveredItemList();
}

The initialization of pickerItems is to the return value of PopulateCollection:

 public List<string> PopulateCollection()
 {
     var myCollection = new List<string>
     {
         "hello",
         "goodbye",
         "please",
         "thank you"
     };

     return myCollection;
 }

That will be the contents of our pickers. We then call PopulateDiscoveredItemList:

 public void PopulateDiscoveredItemList()
 {
     DiscoveredItemList = new List<DiscoveredItem> ()
     {
         new DiscoveredItem {
PickerList = pickerItems, SelectedPickerItem = firstPickerItem, id=1 },
         new DiscoveredItem {
PickerList = pickerItems, SelectedPickerItem = firstPickerItem, id=2 },
         new DiscoveredItem {
PickerList = pickerItems, SelectedPickerItem = firstPickerItem, id=3},   
         new DiscoveredItem {
PickerList = pickerItems, SelectedPickerItem = firstPickerItem, id=4 },  
     };
 }

We now have a list that contains four DiscoveredItems. and which you may remember serves as the ItemsSource for the ListView.

When we run this we want to know the value of the picker when it changes, and we want to know which row that picker was in. As you see just above, when we created the DiscoveredItemList we created four DiscoveredItem instances, each with a unique ID.

To see if this works, put a breakpoint in the setter for SelectedPickerItem inside the DiscoveredItem class. When you first start up, you’ll hit this breakpoint a number of times so you may want to wait to put in the breakpoint until the page settles down.

In any case, once you make a selection in one of the pickers, you’ll hit this breakpoint. Step through until the end of the Setter and examine id (which will be the id of the Discovered Item, and value which will be the selected item in the picker.

I am aware that there a lot of moving parts, and this can be confusing. I do think it will make more sense if you download the source at
https://github.com/JesseLiberty/PickerDemo

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in Essentials, Xamarin and tagged , . Bookmark the permalink.