Adding Databound Pickers to a ListView

Databound Pickers are in much demand, and fortunately Karl Shifflett has created one that is excellent and easy to use.  You add it to your program, wire up the data-binding and  data-bound pickerhey! presto! you’re in business.

The tricky bit comes when you want to put it in a ListView and bind to its contents while still being able to bind to other properties of your objects.

 

Here’s an example based on a program I wrote recently (the names have been changed to protect the guilty)…

Let’s start with our Model.

We have two classes that I’ve stripped down to the essentials.  First is a Person class,

 using System;
 namespace BindablePicker
 {
    public class Person
    {
       public string Name { get; set; }
    }
 } 

I also need to know how many Person objects I have, and since I don’t own the model for Person (it is from an API) I decide to create a PersonHolder class…

 namespace BindablePicker
 {
    public class PersonHolder
    {
       public Person Person { get; set; }
       public int Quantity { get; set; }
    }
 }

Let’s jump to the View Model.  The first thing I need to do is to create a collection of Person Holders, and populate it,

    public class PersonDisplayViewModel : INotifyPropertyChanged
    {
   
       public ObservableCollection<PersonHolder> PersonHolders { get; set; } =
          new ObservableCollection<PersonHolder> ();
 
           PersonHolder personHolder = new PersonHolder ();
          personHolder.Person = new Person () { Name = "Jesse" };
          PersonHolders.Add (personHolder);
 
          personHolder = new PersonHolder ();
          personHolder.Person = new Person () { Name = "Karl" };
          PersonHolders.Add (personHolder);
       }
 

Next, we’ll create an ObservableCollection for the values we want in the picker. Remember, this is a databound picker so we can assign the values dynamically, while the program is running. And we can change them in response to, e.g., events.

Let’s initialize the values in the constructor,

       private ObservableCollection<string> pickerItems;
       public ObservableCollection<string> PickerItems {
          get { return pickerItems; }
          set {
             pickerItems = value;
             RaisePropertyChanged ();
          }
       }
  

       public PersonDisplayViewModel ()
       {
          PickerItems = new ObservableCollection<string> ();
          for (int i = 0; i <= 4; i++) {
             this.PickerItems.Add (i.ToString ());
          }
 

Now comes the fun part, writing the XAML.  The key aspect of the XAML is the ListView.  We begin in the traditional way, making sure to give the ListView a name,

         <ListView
            x:Name=PersonList
            ItemsSource={Binding PersonHolders}>
            <ListView.ItemTemplate>
               <DataTemplate>
                  <ViewCell>
                     <ContentView>
                        <StackLayout
                           Orientation=Horizontal>
                           <Label
                              Text={Binding Person.Name}
                              FontSize=14
                              VerticalTextAlignment=Center />

So far, no problem.  But we want to get the bound value for the picker and that is the entire issue that this post is about.   We do not want to bind the Picker to the PersonHolders, but how do we gain access to the values we do want to bind to.

The answer is to change the BindingContext to the ListView itself.  This sets up the correct relationship with the data,

ItemsSource="{Binding Path=BindingContext.PickerItems, 
                Source={x:Reference PersonList} }"
SelectedItem="{Binding Quantity,  Mode=TwoWay}" />
 

That’s it.  Here’s the complete XAML:

 <?xml version="1.0" encoding="UTF-8"?>
 <ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:BindablePicker;assembly=BindablePicker"
    x:Class="BindablePicker.PersonDisplay">
    <ContentPage.Content>
       <StackLayout
          Margin="50">
          <ListView
             x:Name="PersonList"
             ItemsSource="{Binding PersonHolders}">
             <ListView.ItemTemplate>
                <DataTemplate>
                   <ViewCell>
                      <ContentView>
                         <StackLayout
                            Orientation="Horizontal">
                            <Label
                               Text="{Binding Person.Name}"
                               FontSize="14"
                               VerticalTextAlignment="Center" />
                            <local:BindablePicker
                               ItemsSource="{Binding Path=BindingContext.PickerItems, 
                                          Source={x:Reference PersonList} }"
                               SelectedItem="{Binding Quantity,  Mode=TwoWay}" />
                         </StackLayout>
                      </ContentView>
                   </ViewCell>
                </DataTemplate>
             </ListView.ItemTemplate>
          </ListView>
       </StackLayout>
    </ContentPage.Content>
 </ContentPage> 

Endless thanks to Karl for his invaluable assistance with getting this to work.

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 Xamarin. Bookmark the permalink.

3 Responses to Adding Databound Pickers to a ListView

Comments are closed.