Xamarin Forms - Bindable Picker(!!)
I’m rather starting to like doing these look aheads to features coming out in future versions of Xamarin.Forms. It’s really cool tracing through the source code to see how a new feature is being implemented and coming together. And today we’re going to talk about a feature that I keep trying to use, thinking it’s already implemented in Forms… but every time I try, I slap my forehead and remember it’s not there yet … binding a data source to a Picker
!!
tl;dr;
All the code from this post can be found on GitHub here.
If you’re only here for the goodness of how to data bind to a Picker
… first bind an IList
collection to the ItemsSource
property. Then bind whatever you want receiving updates to the SelectedItem
. Finally, ItemDisplayBinding
can receive another binding (from a property within the class’s that make up the IList
bound to the ItemsSource
), that will determine what gets displayed.
Read on to get the full run down of the new data binding!
New Properties
There are 3 new properties introduced to the Picker
as part of the new data binding functionality (more if you count the backing static BindableProperty
properties, but we don’t need to directly address those). ItemsSource
, SelectedItem
, and ItemDisplayBinding
.
Let’s break them down one by one.
ItemsSource Property
This is an IList
which controls what each element within the Picker
contains. The IList
is not typed to anything – so you could put a list of whatever type you want into the Picker
.
For all the examples that follow, the source of the Picker
is the following:
public class Cheese
{
public string CheeseName { get; set; }
public string Dairy { get; set; }
public CheeseTypes Type { get; set; }
public int Id { get; set; }
static List<Cheese> _allCheeses;
public static List<Cheese> All
{
get
{
if (_allCheeses == null)
{
_allCheeses = new List<Cheese>
{
new Cheese { CheeseName="Little Boy Blue", Dairy="Hooks", Id=1, Type=CheeseTypes.Blue },
new Cheese { CheeseName="10 year", Dairy="Hooks",Id=2, Type=CheeseTypes.Cheddar },
new Cheese { CheeseName="Yellow Curds", Dairy="Murphs", Type=CheeseTypes.Curds },
new Cheese { CheeseName="St Jenifer", Dairy="Creme de la Coule", Type=CheeseTypes.Farmstead }
};
}
return _allCheeses;
}
}
}
It’s a class with a bunch of properties (one of which is an enumeration) and then a static property that returns a pre-populated list of data that we’ll use to bind to something. To set the Picker
up to data bind, the code would look like the following:
<Picker ItemsSource="{x:Static local:Cheese.All}" x:Name="thePicker" />
Of course, set the proper xmlns:local
up to reference the Cheese
class. However, when you run the app, you will see that what is displayed in the Picker
looks like what is on the right. The ItemsSource
is the means of which to populate the Picker
object with data, much in the same way one would do with a ListView
. However, that does not mean what one puts in there will get displayed. If you only put a primitive type … an IList
of string
, an int
, etc. that would get displayed exactly. But if you put a class in, whatever the ToString()
returns will be displayed.
In order to display something meaningful, we need to make use of the ItemDisplayBinding
property.
ItemDisplayBinding Property
The ItemDisplayBinding
property is of a BindingBase
type, and it allows the Picker
to use a property to display text for the options found within the objects it is bound. In other words, ItemDisplayBinding
determines what actually gets displayed within the Picker
.
The trick here is to realize ItemDisplayBinding
is itself a binding (you’d think the name would give it away), so you cannot pass in a string of the property’s name you want to bind to, rather you need to setup another binding. The code to display the CheeseName
property in the Picker
from the example above would look like the following:
<Picker ItemsSource="{x:Static local:Cheese.All}"
ItemDisplayBinding="{Binding CheeseName}" />
Now when the app is run, it displays the following in the picker:
Much better!
Now that we’re able to bind a source to the picker and properly display items, the last piece of the puzzle is to the currently selected item in the picker to a value in a view model. That leads us to SelectedItem
.
SelectedItem Property
SelectedItem
is a property of type object
that changes every time the value within the Picker
is updated. By binding SelectedItem
to a property in a view model, we can note the choice the user makes from the Picker
without any event handling and matching up indexes from the Picker
‘s Items
property to the SelectedIndex
, etc, etc.
The easiest way to see this in action is to define a view model that our view will set to its BindingContext
.
public class FavoriteCheese
{
public Cheese SelectedCheese { get; set; }
}
A very simple view model – only has one property, and that will be the selection from the Picker
. Then to hook it up, all one would need to do, other than setting the BindingContext
, is the following:
<Picker ItemsSource="{x:Static local:Cheese.All}"
ItemDisplayBinding="{Binding CheeseName}"
SelectedItem="{Binding SelectedCheese, Mode=TwoWay}" />
Now every time a new selection is made in the Picker
, a new value is set in the SelectedCheese
property.
And it supports two way binding!
Data binding!
Cool Things
There are a couple of cool things that for some reason or other I wasn’t expecting to happen, but was pleasantly surprised when they did.
- If the
IList
thatItemsSource
binds to is anObservableCollection
– you can add and change the list of options presented in thePicker
at runtime. - You can change the
SelectedItem
in the code behind file and everything works as expected with both the view model andPicker
being updated. - The
SelectedIndexChanged
event does still fire regardless of whether data binding is used or not. - You cannot use the
Items
property to add or change elements if data binding is used.
Summary
Finally it’s here! Data binding for the Picker
! The usage of it will be familiar if you have used binding with ListView
s before. You set the elements to be contained with the ItemsSource
. The subtle differences come in with ItemDisplayBinding
– that tells the Picker which of the properties in the class’ bound to the ItemsSource
to use as the display, otherwise it will use the ToString()
of the class. And SelectedItem
is the means by which you can find out which item has been selected. This will be available in Xamarin.Forms 2.2.4 … Nice!