-
-
Save hjerpbakk/286cfbdd5dfd379a9155 to your computer and use it in GitHub Desktop.
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()); | |
} | |
} | |
} | |
} | |
Could anyone please guide as to how do we use this code above? is there any sample which explains the use of above code?
Thanks
Yeah, exactly what I need.
@jmganesh If you still need the use code, here it is :
<?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:userControls="clr-namespace:myAssembly.UserControls;assembly=myAssembly"
x:Class="myAssembly.Views.ContentPage">
<userControls:BindablePicker ItemsSource="{Binding Path=myCollection}" Selecteditem="{Binding Path=myItem}" />
</ContentPage>
And of course, you need to bind to a ViewModel that contain your Collection and your SelectedItem (with PropertyChanged implementation).
@Odonno, I not really understand how this Bindable Picker works in xaml and ViewModel. Mind to share a very complete basic example on the Binding Path = myCollection and Binding Path = myItem? Thanks.
@EugeneChua91 You can put Path= or not it will be the same thing. It's just for clarity that we can put Path=. You need to Bind to a collection from your ViewModel.
If I want use it using xamarin shared forms getting information from web services example: 2 fields id and description. What must I do?
Works well, cheers!
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");
}
}
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
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??
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
Thanks, this is a really helpful solution.
Thanks for this! Saved me with this. Generic version of create() is no longer supported. Any suggestions how to rewrite?
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...
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());
}
}
}
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:
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,
Nice! Thanks.