diff options
-rw-r--r-- | Xamarin.Forms.Core.UnitTests/PickerTests.cs | 164 | ||||
-rw-r--r-- | Xamarin.Forms.Core/Picker.cs | 412 | ||||
-rw-r--r-- | Xamarin.Forms.Platform.Android/AppCompat/PickerRenderer.cs | 7 | ||||
-rw-r--r-- | Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs | 7 | ||||
-rw-r--r-- | Xamarin.Forms.Platform.WP8/PickerRenderer.cs | 4 | ||||
-rw-r--r-- | Xamarin.Forms.Platform.iOS/Renderers/PickerRenderer.cs | 5 | ||||
-rw-r--r-- | docs/Xamarin.Forms.Core/Xamarin.Forms/Picker.xml | 78 |
7 files changed, 385 insertions, 292 deletions
diff --git a/Xamarin.Forms.Core.UnitTests/PickerTests.cs b/Xamarin.Forms.Core.UnitTests/PickerTests.cs index 01431cdd..6218a3a8 100644 --- a/Xamarin.Forms.Core.UnitTests/PickerTests.cs +++ b/Xamarin.Forms.Core.UnitTests/PickerTests.cs @@ -5,57 +5,57 @@ using System.Globalization; namespace Xamarin.Forms.Core.UnitTests { - internal class ContextFixture + [TestFixture] + public class PickerTests : BaseTestFixture { - public class NestedClass + class PickerTestsContextFixture { - public string Nested { get; set; } - } + public class PickerTestsNestedClass + { + public string Nested { get; set; } + } - public NestedClass Nested { get; set; } + public PickerTestsNestedClass Nested { get; set; } - public string DisplayName { get; set; } + public string DisplayName { get; set; } - public string ComplexName { get; set; } + public string ComplexName { get; set; } - public ContextFixture(string displayName, string complexName) - { - DisplayName = displayName; - ComplexName = complexName; - } + public PickerTestsContextFixture(string displayName, string complexName) + { + DisplayName = displayName; + ComplexName = complexName; + } - public ContextFixture() - { + public PickerTestsContextFixture() + { + } } - } - - internal class BindingContext - { - public ObservableCollection<object> Items { get; set; } - - public object SelectedItem { get; set; } - } - internal class PickerTestValueConverter : IValueConverter - { - public bool ConvertCalled { get; private set; } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + class PickerTestsBindingContext { - ConvertCalled = true; - var cf = (ContextFixture)value; - return cf.DisplayName; + public ObservableCollection<object> Items { get; set; } + + public object SelectedItem { get; set; } } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + class PickerTestValueConverter : IValueConverter { - throw new NotImplementedException(); + public bool ConvertCalled { get; private set; } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + ConvertCalled = true; + var cf = (PickerTestsContextFixture)value; + return cf.DisplayName; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } } - } - [TestFixture] - public class PickerTests : BaseTestFixture - { [Test] public void TestSetSelectedIndexOnNullRows() { @@ -186,28 +186,6 @@ namespace Xamarin.Forms.Core.UnitTests } [Test] - public void TestDisplayFunc() - { - Func<object, string> customDisplayFunc = o => - { - var f = (ContextFixture)o; - return $"{f.DisplayName} ({f.ComplexName})"; - }; - var obj = new ContextFixture("Monkey", "Complex Monkey"); - var picker = new Picker - { - DisplayMemberPath = "Name", - DisplayFunc = customDisplayFunc, - ItemsSource = new ObservableCollection<object> - { - obj - }, - SelectedIndex = 1 - }; - Assert.AreEqual("Monkey (Complex Monkey)", picker.Items[0]); - } - - [Test] public void TestSetItemsSourceProperty() { var items = new ObservableCollection<object> @@ -220,22 +198,22 @@ namespace Xamarin.Forms.Core.UnitTests }; var picker = new Picker { - DisplayMemberPath = "Name", + ItemDisplayBinding = new Binding("Name"), ItemsSource = items }; Assert.AreEqual(5, picker.Items.Count); Assert.AreEqual("John", picker.Items[0]); - Assert.AreEqual("0", picker.Items[3]); + Assert.AreEqual(null, picker.Items[3]); } [Test] public void TestDisplayConverter() { - var obj = new ContextFixture("John", "John Doe"); + var obj = new PickerTestsContextFixture("John", "John Doe"); var converter = new PickerTestValueConverter(); var picker = new Picker { - DisplayConverter = converter, + ItemDisplayBinding = new Binding (Binding.SelfPath, converter:converter), ItemsSource = new ObservableCollection<object> { obj @@ -246,22 +224,6 @@ namespace Xamarin.Forms.Core.UnitTests } [Test] - public void TestDisplayMemberPathShouldThrowArgumentExceptionInvalidPath() - { - var obj = new ContextFixture("Monkey", "Complex Monkey"); - Func<Picker> picker = () => new Picker - { - DisplayMemberPath = "Name", - ItemsSource = new ObservableCollection<object> - { - obj - }, - SelectedIndex = 1 - }; - Assert.Throws<ArgumentException>(() => picker()); - } - - [Test] public void TestItemsSourceCollectionChangedAppend() { var items = new ObservableCollection<object> @@ -272,7 +234,7 @@ namespace Xamarin.Forms.Core.UnitTests }; var picker = new Picker { - DisplayMemberPath = "Name", + ItemDisplayBinding = new Binding("Name"), ItemsSource = items, SelectedIndex = 0 }; @@ -294,7 +256,7 @@ namespace Xamarin.Forms.Core.UnitTests }; var picker = new Picker { - DisplayMemberPath = "Name", + ItemDisplayBinding = new Binding("Name"), ItemsSource = items, SelectedIndex = 0 }; @@ -314,7 +276,7 @@ namespace Xamarin.Forms.Core.UnitTests }; var picker = new Picker { - DisplayMemberPath = "Name", + ItemDisplayBinding = new Binding("Name"), ItemsSource = items, SelectedIndex = 0 }; @@ -337,7 +299,7 @@ namespace Xamarin.Forms.Core.UnitTests var bindingContext = new { Items = items }; var picker = new Picker { - DisplayMemberPath = "Name", + ItemDisplayBinding = new Binding("Name"), BindingContext = bindingContext }; picker.SetBinding(Picker.ItemsSourceProperty, "Items"); @@ -348,6 +310,7 @@ namespace Xamarin.Forms.Core.UnitTests "Orange" }; picker.BindingContext = new { Items = items }; + picker.ItemDisplayBinding = null; Assert.AreEqual(2, picker.Items.Count); Assert.AreEqual("Peach", picker.Items[0]); } @@ -358,12 +321,12 @@ namespace Xamarin.Forms.Core.UnitTests var items = new ObservableCollection<object> { new { Name = "John" }, - "Paul", - "Ringo" + new { Name = "Paul" }, + new { Name = "Ringo"}, }; var picker = new Picker { - DisplayMemberPath = "Name", + ItemDisplayBinding = new Binding("Name"), ItemsSource = items, SelectedIndex = 0 }; @@ -395,11 +358,11 @@ namespace Xamarin.Forms.Core.UnitTests [Test] public void TestSelectedItemDefault() { - var bindingContext = new BindingContext + var bindingContext = new PickerTestsBindingContext { Items = new ObservableCollection<object> { - new ContextFixture("John", "John") + new PickerTestsContextFixture("John", "John") } }; var picker = new Picker @@ -414,18 +377,27 @@ namespace Xamarin.Forms.Core.UnitTests } [Test] + public void ThrowsWhenModifyingItemsIfItemsSourceIsSet() + { + var picker = new Picker { + ItemsSource = new System.Collections.Generic.List<object> () + }; + Assert.Throws<InvalidOperationException>(() => picker.Items.Add("foo")); + } + + [Test] public void TestNestedDisplayMemberPathExpression() { - var obj = new ContextFixture + var obj = new PickerTestsContextFixture { - Nested = new ContextFixture.NestedClass + Nested = new PickerTestsContextFixture.PickerTestsNestedClass { Nested = "NestedProperty" } }; var picker = new Picker { - DisplayMemberPath = "Nested.Nested", + ItemDisplayBinding = new Binding("Nested.Nested"), ItemsSource = new ObservableCollection<object> { obj @@ -454,8 +426,8 @@ namespace Xamarin.Forms.Core.UnitTests [Test] public void TestSelectedItemSet() { - var obj = new ContextFixture("John", "John"); - var bindingContext = new BindingContext + var obj = new PickerTestsContextFixture("John", "John"); + var bindingContext = new PickerTestsBindingContext { Items = new ObservableCollection<object> { @@ -466,7 +438,7 @@ namespace Xamarin.Forms.Core.UnitTests var picker = new Picker { BindingContext = bindingContext, - DisplayMemberPath = "DisplayName" + ItemDisplayBinding = new Binding("DisplayName"), }; picker.SetBinding(Picker.ItemsSourceProperty, "Items"); picker.SetBinding(Picker.SelectedItemProperty, "SelectedItem"); @@ -478,8 +450,8 @@ namespace Xamarin.Forms.Core.UnitTests [Test] public void TestSelectedItemChangeSelectedIndex() { - var obj = new ContextFixture("John", "John"); - var bindingContext = new BindingContext + var obj = new PickerTestsContextFixture("John", "John"); + var bindingContext = new PickerTestsBindingContext { Items = new ObservableCollection<object> { @@ -489,7 +461,7 @@ namespace Xamarin.Forms.Core.UnitTests var picker = new Picker { BindingContext = bindingContext, - DisplayMemberPath = "DisplayName" + ItemDisplayBinding = new Binding("DisplayName"), }; picker.SetBinding(Picker.ItemsSourceProperty, "Items"); picker.SetBinding(Picker.SelectedItemProperty, "SelectedItem"); diff --git a/Xamarin.Forms.Core/Picker.cs b/Xamarin.Forms.Core/Picker.cs index 3816bedf..56dc4d1a 100644 --- a/Xamarin.Forms.Core/Picker.cs +++ b/Xamarin.Forms.Core/Picker.cs @@ -2,8 +2,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using System.Globalization; -using System.Reflection; using Xamarin.Forms.Platform; namespace Xamarin.Forms @@ -11,63 +9,33 @@ namespace Xamarin.Forms [RenderWith(typeof(_PickerRenderer))] public class Picker : View, IElementConfiguration<Picker> { - public static readonly BindableProperty TextColorProperty = BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(Picker), Color.Default); + public static readonly BindableProperty TextColorProperty = + BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(Picker), Color.Default); - public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(Picker), default(string)); + public static readonly BindableProperty TitleProperty = + BindableProperty.Create(nameof(Title), typeof(string), typeof(Picker), default(string)); - public static readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(nameof(SelectedIndex), typeof(int), typeof(Picker), -1, BindingMode.TwoWay, - propertyChanged: OnSelectedIndexChanged, - coerceValue: CoerceSelectedIndex); + public static readonly BindableProperty SelectedIndexProperty = + BindableProperty.Create(nameof(SelectedIndex), typeof(int), typeof(Picker), -1, BindingMode.TwoWay, + propertyChanged: OnSelectedIndexChanged, coerceValue: CoerceSelectedIndex); - public static readonly BindableProperty SelectedValueMemberPathProperty = BindableProperty.Create(nameof(SelectedValueMemberPath), typeof(string), typeof(Picker)); + public static readonly BindableProperty ItemsSourceProperty = + BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(Picker), default(IList), + propertyChanged: OnItemsSourceChanged); - public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(Picker), default(IList), propertyChanged: OnItemsSourceChanged); - - public static readonly BindableProperty DisplayMemberPathProperty = BindableProperty.Create(nameof(DisplayMemberPath), typeof(string), typeof(Picker), propertyChanged: OnDisplayMemberPathChanged); - - public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(Picker), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged); + public static readonly BindableProperty SelectedItemProperty = + BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(Picker), null, BindingMode.TwoWay, + propertyChanged: OnSelectedItemChanged); readonly Lazy<PlatformConfigurationRegistry<Picker>> _platformConfigurationRegistry; - public static readonly BindableProperty DisplayFuncProperty = - BindableProperty.Create( - nameof(DisplayFunc), - typeof(Func<object, string>), - typeof(Picker)); - - public static readonly BindableProperty DisplayConverterProperty = - BindableProperty.Create( - nameof(DisplayConverter), - typeof(IValueConverter), - typeof(Picker), - default(IValueConverter)); - - public Picker() { - ((ObservableList<string>)Items).CollectionChanged += OnItemsCollectionChanged; + ((INotifyCollectionChanged)Items).CollectionChanged += OnItemsCollectionChanged; _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Picker>>(() => new PlatformConfigurationRegistry<Picker>(this)); } - public string DisplayMemberPath - { - get { return (string)GetValue(DisplayMemberPathProperty); } - set { SetValue(DisplayMemberPathProperty, value); } - } - - public Func<object, string> DisplayFunc - { - get { return (Func<object, string>)GetValue(DisplayFuncProperty); } - set { SetValue(DisplayFuncProperty, value); } - } - - public IValueConverter DisplayConverter - { - get { return (IValueConverter)GetValue(DisplayConverterProperty); } - set { SetValue(DisplayConverterProperty, value); } - } - - public IList<string> Items { get; } = new ObservableList<string>(); + public IList<string> Items { get; } = new LockableObservableListWrapper(); public IList ItemsSource { @@ -87,73 +55,44 @@ namespace Xamarin.Forms set { SetValue(SelectedItemProperty, value); } } - public string SelectedValueMemberPath - { - get { return (string)GetValue(SelectedValueMemberPathProperty); } - set { SetValue(SelectedValueMemberPathProperty, value); } - } - - public Color TextColor - { + public Color TextColor { get { return (Color)GetValue(TextColorProperty); } set { SetValue(TextColorProperty, value); } } - public string Title - { + public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } - public event EventHandler SelectedIndexChanged; + BindingBase _itemDisplayBinding; + public BindingBase ItemDisplayBinding { + get { return _itemDisplayBinding; } + set { + if (_itemDisplayBinding == value) + return; - protected virtual string GetDisplayMember(object item) - { - if (DisplayConverter != null) - { - var display = DisplayConverter.Convert(item, typeof(string), null, CultureInfo.CurrentUICulture) as string; - if (display == null) - { - throw new ArgumentException("value must be converted to string"); - } - return display; - } - if (DisplayFunc != null) - { - return DisplayFunc(item); - } - if (item == null) - { - return null; + OnPropertyChanging(); + var oldValue = value; + _itemDisplayBinding = value; + OnItemDisplayBindingChanged(oldValue, _itemDisplayBinding); + OnPropertyChanged(); } - bool isValueType = item.GetType().GetTypeInfo().IsValueType; - if (isValueType || string.IsNullOrEmpty(DisplayMemberPath) || item is string) - { - // For a mix of objects in ItemsSourc to be handled correctly in conjunction with DisplayMemberPath - // we need to handle value types and string so that GetPropertyValue doesn't throw exception if the property - // doesn't exist on the item object - return item.ToString(); - } - return GetPropertyValue(item, DisplayMemberPath) as string; } - void AddItems(NotifyCollectionChangedEventArgs e) - { - int index = e.NewStartingIndex < 0 ? Items.Count : e.NewStartingIndex; - foreach (object newItem in e.NewItems) - { - Items.Insert(index++, GetDisplayMember(newItem)); - } - } + public event EventHandler SelectedIndexChanged; + + static readonly BindableProperty s_displayProperty = + BindableProperty.Create("Display", typeof(string), typeof(Picker), default(string)); - void BindItems() + string GetDisplayMember(object item) { - Items.Clear(); - foreach (object item in ItemsSource) - { - Items.Add(GetDisplayMember(item)); - } - UpdateSelectedItem(); + if (ItemDisplayBinding == null) + return item.ToString(); + + ItemDisplayBinding.Apply(item, this, s_displayProperty); + ItemDisplayBinding.Unapply(); + return (string)GetValue(s_displayProperty); } static object CoerceSelectedIndex(BindableObject bindable, object value) @@ -162,95 +101,84 @@ namespace Xamarin.Forms return picker.Items == null ? -1 : ((int)value).Clamp(-1, picker.Items.Count - 1); } - void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + void OnItemDisplayBindingChanged(BindingBase oldValue, BindingBase newValue) { - switch (e.Action) - { - case NotifyCollectionChangedAction.Move: - case NotifyCollectionChangedAction.Replace: - case NotifyCollectionChangedAction.Reset: - // Clear Items collection and re-populate it with values from ItemsSource - BindItems(); - return; - case NotifyCollectionChangedAction.Remove: - RemoveItems(e); - break; - case NotifyCollectionChangedAction.Add: - AddItems(e); - break; - default: - throw new ArgumentOutOfRangeException(); - } + ResetItems(); } - static object GetPropertyValue(object item, string memberPath) + void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } - if (string.IsNullOrEmpty(memberPath)) - { - throw new ArgumentNullException(nameof(memberPath)); + SelectedIndex = SelectedIndex.Clamp(-1, Items.Count - 1); + UpdateSelectedItem(); + } + + static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue) + { + ((Picker)bindable).OnItemsSourceChanged((IList)oldValue, (IList)newValue); + } + + void OnItemsSourceChanged(IList oldValue, IList newValue) + { + var oldObservable = oldValue as INotifyCollectionChanged; + if (oldObservable != null) + oldObservable.CollectionChanged -= CollectionChanged; + + var newObservable = newValue as INotifyCollectionChanged; + if (newObservable != null) { + newObservable.CollectionChanged += CollectionChanged; } - // Find the property by walking the display member path to find any nested properties - string[] propertyPathParts = memberPath.Split('.'); - object propertyValue = item; - foreach (string propertyPathPart in propertyPathParts) - { - PropertyInfo propInfo = propertyValue.GetType().GetTypeInfo().GetDeclaredProperty(propertyPathPart); - if (propInfo == null) - { - throw new ArgumentException( - $"No property with name '{propertyPathPart}' was found on '{propertyValue.GetType().FullName}'"); - } - propertyValue = propInfo.GetValue(propertyValue); + + if (newValue != null) { + ((LockableObservableListWrapper)Items).IsLocked = true; + ResetItems(); + } else { + ((LockableObservableListWrapper)Items).InternalClear(); + ((LockableObservableListWrapper)Items).IsLocked = false; } - return propertyValue; } - static void OnDisplayMemberPathChanged(BindableObject bindable, object oldValue, object newValue) + void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - var picker = (Picker)bindable; - if (picker.ItemsSource?.Count > 0) - { - picker.BindItems(); + switch (e.Action) { + case NotifyCollectionChangedAction.Add: + AddItems(e); + break; + case NotifyCollectionChangedAction.Remove: + RemoveItems(e); + break; + default: //Move, Replace, Reset + ResetItems(); + break; } } + void AddItems(NotifyCollectionChangedEventArgs e) + { + int index = e.NewStartingIndex < 0 ? Items.Count : e.NewStartingIndex; + foreach (object newItem in e.NewItems) + ((LockableObservableListWrapper)Items).InternalInsert(index++, GetDisplayMember(newItem)); + } - void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + void RemoveItems(NotifyCollectionChangedEventArgs e) { - SelectedIndex = SelectedIndex.Clamp(-1, Items.Count - 1); - UpdateSelectedItem(); + int index = e.OldStartingIndex < Items.Count ? e.OldStartingIndex : Items.Count; + foreach (object _ in e.OldItems) + ((LockableObservableListWrapper)Items).InternalRemoveAt(index--); } - static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue) + void ResetItems() { - var picker = (Picker)bindable; - // Check if the ItemsSource value has changed and if so, unsubscribe from collection changed - var observable = oldValue as INotifyCollectionChanged; - if (observable != null) - { - observable.CollectionChanged -= picker.CollectionChanged; - } - observable = newValue as INotifyCollectionChanged; - if (observable != null) - { - observable.CollectionChanged += picker.CollectionChanged; - picker.BindItems(); - } - else - { - // newValue is null so clear the items collection - picker.Items.Clear(); - } + if (ItemsSource == null) + return; + ((LockableObservableListWrapper)Items).InternalClear(); + foreach (object item in ItemsSource) + ((LockableObservableListWrapper)Items).InternalAdd(GetDisplayMember(item)); + UpdateSelectedItem(); } static void OnSelectedIndexChanged(object bindable, object oldValue, object newValue) { var picker = (Picker)bindable; - EventHandler eh = picker.SelectedIndexChanged; - eh?.Invoke(bindable, EventArgs.Empty); + picker.SelectedIndexChanged?.Invoke(bindable, EventArgs.Empty); picker.UpdateSelectedItem(); } @@ -260,34 +188,146 @@ namespace Xamarin.Forms picker.UpdateSelectedIndex(newValue); } - void RemoveItems(NotifyCollectionChangedEventArgs e) - { - int index = e.OldStartingIndex < Items.Count ? e.OldStartingIndex : Items.Count; - // TODO: How do we determine the order of which the items were removed - foreach (object _ in e.OldItems) - { - Items.RemoveAt(index--); - } - } - void UpdateSelectedIndex(object selectedItem) { - string displayMember = GetDisplayMember(selectedItem); - int index = Items.IndexOf(displayMember); - // TODO Should we prevent call to FindObject since the object is already known - // by setting a flag, or otherwise indicate, that we, internally, forced a SelectedIndex changed - SelectedIndex = index; + if (ItemsSource != null) { + SelectedIndex = ItemsSource.IndexOf(selectedItem); + return; + } + SelectedIndex = Items.IndexOf(selectedItem); } void UpdateSelectedItem() { - // coerceSelectedIndex ensures that SelectedIndex is in range [-1,ItemsSource.Count) - SelectedItem = SelectedIndex == -1 ? null : ItemsSource?[SelectedIndex]; + if (SelectedIndex == -1) { + SelectedItem = null; + return; + } + + if (ItemsSource != null) { + SelectedItem = ItemsSource [SelectedIndex]; + return; + } + + SelectedItem = Items [SelectedIndex]; } public IPlatformElementConfiguration<T, Picker> On<T>() where T : IConfigPlatform { return _platformConfigurationRegistry.Value.On<T>(); } + + class LockableObservableListWrapper : INotifyCollectionChanged, IList<string> + { + readonly ObservableList<string> _list = new ObservableList<string>(); + + public bool IsLocked { get; set; } + + event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged { + add { _list.CollectionChanged += value; } + remove { _list.CollectionChanged -= value; } + } + + void ThrowOnLocked() + { + if (IsLocked) + throw new InvalidOperationException("The Items list can not be manipulated if the ItemsSource property is set"); + + } + public string this [int index] { + get { return _list [index]; } + set { + ThrowOnLocked(); + _list [index] = value; } + } + + public int Count { + get { return _list.Count; } + } + + public bool IsReadOnly { + get { return ((IList<string>)_list).IsReadOnly; } + } + + public void InternalAdd(string item) + { + _list.Add(item); + } + + public void Add(string item) + { + ThrowOnLocked(); + InternalAdd(item); + } + + public void InternalClear() + { + _list.Clear(); + } + + public void Clear() + { + ThrowOnLocked(); + InternalClear(); + } + + public bool Contains(string item) + { + return _list.Contains(item); + } + + public void CopyTo(string [] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public IEnumerator<string> GetEnumerator() + { + return _list.GetEnumerator(); + } + + public int IndexOf(string item) + { + return _list.IndexOf(item); + } + + public void InternalInsert(int index, string item) + { + _list.Insert(index, item); + } + + public void Insert(int index, string item) + { + ThrowOnLocked(); + InternalInsert(index, item); + } + + public bool InternalRemove(string item) + { + return _list.Remove(item); + } + + public bool Remove(string item) + { + ThrowOnLocked(); + return InternalRemove(item); + } + + public void InternalRemoveAt(int index) + { + _list.RemoveAt(index); + } + + public void RemoveAt(int index) + { + ThrowOnLocked(); + InternalRemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_list).GetEnumerator(); + } + } } -} +}
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/AppCompat/PickerRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/PickerRenderer.cs index 6650d9e6..9587d0ad 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/PickerRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/PickerRenderer.cs @@ -6,6 +6,7 @@ using Android.Content.Res; using Android.Text; using Android.Widget; using Object = Java.Lang.Object; +using System.Collections.Specialized; namespace Xamarin.Forms.Platform.Android.AppCompat { @@ -31,7 +32,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat { _disposed = true; - ((ObservableList<string>)Element.Items).CollectionChanged -= RowsCollectionChanged; + ((INotifyCollectionChanged)Element.Items).CollectionChanged -= RowsCollectionChanged; } base.Dispose(disposing); @@ -40,11 +41,11 @@ namespace Xamarin.Forms.Platform.Android.AppCompat protected override void OnElementChanged(ElementChangedEventArgs<Picker> e) { if (e.OldElement != null) - ((ObservableList<string>)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged; + ((INotifyCollectionChanged)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged; if (e.NewElement != null) { - ((ObservableList<string>)e.NewElement.Items).CollectionChanged += RowsCollectionChanged; + ((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged; if (Control == null) { EditText textField = CreateNativeControl(); diff --git a/Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs index b6d81718..edfe9e7b 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs @@ -9,6 +9,7 @@ using ADatePicker = Android.Widget.DatePicker; using ATimePicker = Android.Widget.TimePicker; using Object = Java.Lang.Object; using Orientation = Android.Widget.Orientation; +using System.Collections.Specialized; namespace Xamarin.Forms.Platform.Android { @@ -30,7 +31,7 @@ namespace Xamarin.Forms.Platform.Android if (disposing && !_isDisposed) { _isDisposed = true; - ((ObservableList<string>)Element.Items).CollectionChanged -= RowsCollectionChanged; + ((INotifyCollectionChanged)Element.Items).CollectionChanged -= RowsCollectionChanged; } base.Dispose(disposing); @@ -44,11 +45,11 @@ namespace Xamarin.Forms.Platform.Android protected override void OnElementChanged(ElementChangedEventArgs<Picker> e) { if (e.OldElement != null) - ((ObservableList<string>)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged; + ((INotifyCollectionChanged)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged; if (e.NewElement != null) { - ((ObservableList<string>)e.NewElement.Items).CollectionChanged += RowsCollectionChanged; + ((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged; if (Control == null) { var textField = CreateNativeControl(); diff --git a/Xamarin.Forms.Platform.WP8/PickerRenderer.cs b/Xamarin.Forms.Platform.WP8/PickerRenderer.cs index 5dc1d838..8b904fed 100644 --- a/Xamarin.Forms.Platform.WP8/PickerRenderer.cs +++ b/Xamarin.Forms.Platform.WP8/PickerRenderer.cs @@ -27,9 +27,9 @@ namespace Xamarin.Forms.Platform.WinPhone base.OnElementChanged(e); if (e.OldElement != null) - ((ObservableList<string>)Element.Items).CollectionChanged -= ItemsCollectionChanged; + ((INotifyCollectionChanged)Element.Items).CollectionChanged -= ItemsCollectionChanged; - ((ObservableList<string>)Element.Items).CollectionChanged += ItemsCollectionChanged; + ((INotifyCollectionChanged)Element.Items).CollectionChanged += ItemsCollectionChanged; _listPicker.ItemTemplate = (System.Windows.DataTemplate)System.Windows.Application.Current.Resources["PickerItemTemplate"]; _listPicker.FullModeItemTemplate = (System.Windows.DataTemplate)System.Windows.Application.Current.Resources["PickerFullItemTemplate"]; diff --git a/Xamarin.Forms.Platform.iOS/Renderers/PickerRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/PickerRenderer.cs index d0cc4ece..5a7fa22d 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/PickerRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/PickerRenderer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Specialized; using System.ComponentModel; using UIKit; using RectangleF = CoreGraphics.CGRect; @@ -15,7 +16,7 @@ namespace Xamarin.Forms.Platform.iOS protected override void OnElementChanged(ElementChangedEventArgs<Picker> e) { if (e.OldElement != null) - ((ObservableList<string>)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged; + ((INotifyCollectionChanged)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged; if (e.NewElement != null) { @@ -55,7 +56,7 @@ namespace Xamarin.Forms.Platform.iOS UpdatePicker(); UpdateTextColor(); - ((ObservableList<string>)e.NewElement.Items).CollectionChanged += RowsCollectionChanged; + ((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged; } base.OnElementChanged(e); diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/Picker.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/Picker.xml index d8507d62..08b70ed6 100644 --- a/docs/Xamarin.Forms.Core/Xamarin.Forms/Picker.xml +++ b/docs/Xamarin.Forms.Core/Xamarin.Forms/Picker.xml @@ -163,6 +163,22 @@ namespace FormsGallery </remarks> </Docs> </Member> + <Member MemberName="ItemDisplayBinding"> + <MemberSignature Language="C#" Value="public Xamarin.Forms.BindingBase ItemDisplayBinding { get; set; }" /> + <MemberSignature Language="ILAsm" Value=".property instance class Xamarin.Forms.BindingBase ItemDisplayBinding" /> + <MemberType>Property</MemberType> + <AssemblyInfo> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <ReturnValue> + <ReturnType>Xamarin.Forms.BindingBase</ReturnType> + </ReturnValue> + <Docs> + <summary>To be added.</summary> + <value>To be added.</value> + <remarks>To be added.</remarks> + </Docs> + </Member> <Member MemberName="Items"> <MemberSignature Language="C#" Value="public System.Collections.Generic.IList<string> Items { get; }" /> <MemberSignature Language="ILAsm" Value=".property instance class System.Collections.Generic.IList`1<string> Items" /> @@ -185,6 +201,37 @@ namespace FormsGallery <remarks>This property is read-only, but exposes the IList<> interface, so items can be added using Add().</remarks> </Docs> </Member> + <Member MemberName="ItemsSource"> + <MemberSignature Language="C#" Value="public System.Collections.IList ItemsSource { get; set; }" /> + <MemberSignature Language="ILAsm" Value=".property instance class System.Collections.IList ItemsSource" /> + <MemberType>Property</MemberType> + <AssemblyInfo> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <ReturnValue> + <ReturnType>System.Collections.IList</ReturnType> + </ReturnValue> + <Docs> + <summary>To be added.</summary> + <value>To be added.</value> + <remarks>To be added.</remarks> + </Docs> + </Member> + <Member MemberName="ItemsSourceProperty"> + <MemberSignature Language="C#" Value="public static readonly Xamarin.Forms.BindableProperty ItemsSourceProperty;" /> + <MemberSignature Language="ILAsm" Value=".field public static initonly class Xamarin.Forms.BindableProperty ItemsSourceProperty" /> + <MemberType>Field</MemberType> + <AssemblyInfo> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <ReturnValue> + <ReturnType>Xamarin.Forms.BindableProperty</ReturnType> + </ReturnValue> + <Docs> + <summary>To be added.</summary> + <remarks>To be added.</remarks> + </Docs> + </Member> <Member MemberName="On<T>"> <MemberSignature Language="C#" Value="public Xamarin.Forms.IPlatformElementConfiguration<T,Xamarin.Forms.Picker> On<T> () where T : Xamarin.Forms.IConfigPlatform;" /> <MemberSignature Language="ILAsm" Value=".method public hidebysig newslot virtual instance class Xamarin.Forms.IPlatformElementConfiguration`2<!!T, class Xamarin.Forms.Picker> On<(class Xamarin.Forms.IConfigPlatform) T>() cil managed" /> @@ -275,6 +322,37 @@ namespace FormsGallery </remarks> </Docs> </Member> + <Member MemberName="SelectedItem"> + <MemberSignature Language="C#" Value="public object SelectedItem { get; set; }" /> + <MemberSignature Language="ILAsm" Value=".property instance object SelectedItem" /> + <MemberType>Property</MemberType> + <AssemblyInfo> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <ReturnValue> + <ReturnType>System.Object</ReturnType> + </ReturnValue> + <Docs> + <summary>To be added.</summary> + <value>To be added.</value> + <remarks>To be added.</remarks> + </Docs> + </Member> + <Member MemberName="SelectedItemProperty"> + <MemberSignature Language="C#" Value="public static readonly Xamarin.Forms.BindableProperty SelectedItemProperty;" /> + <MemberSignature Language="ILAsm" Value=".field public static initonly class Xamarin.Forms.BindableProperty SelectedItemProperty" /> + <MemberType>Field</MemberType> + <AssemblyInfo> + <AssemblyVersion>2.0.0.0</AssemblyVersion> + </AssemblyInfo> + <ReturnValue> + <ReturnType>Xamarin.Forms.BindableProperty</ReturnType> + </ReturnValue> + <Docs> + <summary>To be added.</summary> + <remarks>To be added.</remarks> + </Docs> + </Member> <Member MemberName="TextColor"> <MemberSignature Language="C#" Value="public Xamarin.Forms.Color TextColor { get; set; }" /> <MemberSignature Language="ILAsm" Value=".property instance valuetype Xamarin.Forms.Color TextColor" /> |