Skip to content

Instantly share code, notes, and snippets.

@hjerpbakk
Created July 17, 2014 19:26
Show Gist options
  • Save hjerpbakk/286cfbdd5dfd379a9155 to your computer and use it in GitHub Desktop.
Save hjerpbakk/286cfbdd5dfd379a9155 to your computer and use it in GitHub Desktop.
A Picker-control for Xamarin.Forms which enables data binding through an ItemsSource and the SelectedItem.
using System;
using Xamarin.Forms;
using System.Collections;
namespace YourNamespace.Views.Controls {
public class BindablePicker : Picker
{
public BindablePicker()
{
this.SelectedIndexChanged += OnSelectedIndexChanged;
}
public static BindableProperty ItemsSourceProperty =
BindableProperty.Create<BindablePicker, IEnumerable>(o => o.ItemsSource, default(IEnumerable), propertyChanged: OnItemsSourceChanged);
public static BindableProperty SelectedItemProperty =
BindableProperty.Create<BindablePicker, object>(o => o.SelectedItem, default(object),propertyChanged: OnSelectedItemChanged);
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
private static void OnItemsSourceChanged(BindableObject bindable, IEnumerable oldvalue, IEnumerable newvalue)
{
var picker = bindable as BindablePicker;
picker.Items.Clear();
if (newvalue != null)
{
//now it works like "subscribe once" but you can improve
foreach (var item in newvalue)
{
picker.Items.Add(item.ToString());
}
}
}
private void OnSelectedIndexChanged(object sender, EventArgs eventArgs)
{
if (SelectedIndex < 0 || SelectedIndex > Items.Count - 1)
{
SelectedItem = null;
}
else
{
SelectedItem = Items[SelectedIndex];
}
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var picker = bindable as BindablePicker;
if (newvalue != null)
{
picker.SelectedIndex = picker.Items.IndexOf(newvalue.ToString());
}
}
}
}
@xtellurian
Copy link

Works well, cheers!

@khanzzirfan
Copy link

Can someone review the code below, if I have implemented bindings correctly

    private ObservableCollection<string> _myCollection;
    public ObservableCollection<string> myCollection {
        get
        {
            return _myCollection;
        }
        set
        {
            _myCollection = value;
            OnPropertyChanged("myCollection");
        }
    }



    private string _myitem;
    public string myItem
    {
        get
        {
            return _myitem;
        }
        set
        {
            _myitem = value;
            OnPropertyChanged("myItem");
        }
    }

@khanzzirfan
Copy link

Hi,
Currently the below code works from IOS simulator and showing picker values and save data.
myCollection .Clear();
var timepickerlist = GetTimeList().ToList();
foreach (var t in timepickerlist)
{
myCollection.Add(t);
}

But the above code does not work in Android emulators. I have to modify the above code as
myCollection = new ObservableCollection(timepickerlist);

Could someone point me if there is a better way to achieve the above code and populating observable collection.

Regards,
Irfan

@julesx
Copy link

julesx commented Feb 3, 2016

There are a ton of BindablePicker implementations for XF, but none of them handle collection changed events after render. Someone please!!

//now it works like "subscribe once" but you can improve

how??

@DrEmigius
Copy link

You should set the BindingMode of SelectedItemProperty to "TwoWay", so the SelectedItem can also be set by the picker.
Otherwise OnSelectedIndexChanged will never update the SelectedItem binding target even though the value of the picker has changed.

Greetings,
Dennis

@johnslaby
Copy link

Thanks, this is a really helpful solution.

@rump1992
Copy link

Thanks for this! Saved me with this. Generic version of create() is no longer supported. Any suggestions how to rewrite?

@StillLearnin
Copy link

StillLearnin commented Jun 13, 2016

Generic version of create() is no longer supported. Any suggestions how to rewrite?

        public static BindableProperty ItemsSourceProperty =
            BindableProperty.Create<BindablePicker, IEnumerable>(o => o.ItemsSource, default(IEnumerable), propertyChanged: OnItemsSourceChanged);

Same question here...

@robece
Copy link

robece commented Jun 17, 2016

I did some modifications to avoid the use of the deprecated Create<> method:

   public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create("ItemsSource", typeof(List<string>), typeof(BindablePicker), null, BindingMode.OneWay, null, propertyChanged: OnItemsSourceChanged);

    private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var picker = bindable as BindablePicker;
        picker.Items.Clear();
        if ((List<string>) newValue != null)
        {
            //now it works like "subscribe once" but you can improve
            foreach (var item in (List<string>)newValue)
            {
                picker.Items.Add(item.ToString());
            }
        }
    }

@scastria
Copy link

I think this implementation has a bug! Line 53 in the code listing at the top sets the SelectedItem to Items[SelectedIndex]. This is wrong as Items[] is the base class Picker collection which are STRINGS. The user of this BindablePicker class will expect the SelectedItem to be one of the items that he supplied in the ItemsSource property which is an object. Therefore, Line 53 should set SelectedItem to ItemsSource[SelectedIndex] which also requires changing ItemsSource from IEnumerable to IList.

See this Xamarin forum post for more details:

http://forums.xamarin.com/discussion/70172/bindable-picker-control-not-updating-bound-property#latest

@erportico
Copy link

erportico commented Aug 22, 2016

Hi guys,
I have a problem when I try to bind. The error is:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.

I can't understand why.
Thank you in advance,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment