Add DropdownList 60/116460/6
authorjh5.cho <jh5.cho@samsung.com>
Fri, 24 Feb 2017 10:20:00 +0000 (19:20 +0900)
committerjh5.cho <jh5.cho@samsung.com>
Thu, 16 Mar 2017 13:19:00 +0000 (22:19 +0900)
    - RFC: http://suprem.sec.samsung.net/confluence/display/SPTDTLC/%5BFormsTizen%5D+RFC+21+-+DropDownList

Change-Id: I2622f567b39c02cee3b0f04a9bc14b8f094f5c9a

Tizen.Xamarin.Forms.Extension.Renderer/DropdownListRenderer.cs [new file with mode: 0755]
Tizen.Xamarin.Forms.Extension.Renderer/Tizen.Xamarin.Forms.Extension.Renderer.csproj
Tizen.Xamarin.Forms.Extension/DropdownList.cs [new file with mode: 0755]
Tizen.Xamarin.Forms.Extension/Tizen.Xamarin.Forms.Extension.csproj

diff --git a/Tizen.Xamarin.Forms.Extension.Renderer/DropdownListRenderer.cs b/Tizen.Xamarin.Forms.Extension.Renderer/DropdownListRenderer.cs
new file mode 100755 (executable)
index 0000000..594fb82
--- /dev/null
@@ -0,0 +1,149 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Linq;
+using Tizen.Xamarin.Forms.Extension;
+using Tizen.Xamarin.Forms.Extension.Renderer;
+using Xamarin.Forms.Platform.Tizen;
+using EHoversel = ElmSharp.Hoversel;
+using TForms = Xamarin.Forms.Platform.Tizen.Forms;
+
+[assembly: ExportRenderer(typeof(DropdownList), typeof(DropdownListRenderer))]
+namespace Tizen.Xamarin.Forms.Extension.Renderer
+{
+    public class DropdownListRenderer : ViewRenderer<DropdownList, EHoversel>
+    {
+        Dictionary<ElmSharp.HoverselItem, object> _items = new Dictionary<ElmSharp.HoverselItem, object>();
+
+        public DropdownListRenderer()
+        {
+        }
+
+        protected override void OnElementChanged(ElementChangedEventArgs<DropdownList> e)
+        {
+            if (Control == null)
+            {
+                var dropdownList = new EHoversel(TForms.Context.MainWindow);
+                SetNativeControl(dropdownList);
+            }
+            if (e.OldElement != null)
+            {
+                ((ObservableCollection<object>)e.OldElement.InternalItems).CollectionChanged -= OnCollectionChanged;
+                Control.ItemSelected -= ItemSelectedEventHandler;
+                Control.Dismissed -= OnDismissed;
+            }
+            if (e.NewElement != null)
+            {
+                ((ObservableCollection<object>)e.NewElement.InternalItems).CollectionChanged += OnCollectionChanged;
+                Control.ItemSelected += ItemSelectedEventHandler;
+                Control.Dismissed += OnDismissed;
+
+                Control.HoverParent = Platform.GetRenderer(Element.Parent)?.NativeView;
+
+                ClearItems();
+                AddItems(e.NewElement.InternalItems);
+
+                UpdateIsHorizontal();
+                UpdateIsExpanded();
+            }
+            base.OnElementChanged(e);
+        }
+
+        void ItemSelectedEventHandler(object sender, ElmSharp.HoverselItemEventArgs e)
+        {
+            Element.SelectedItem = _items[e.Item];
+        }
+
+        void OnDismissed(object sender, EventArgs e)
+        {
+            Element.IsExpanded = false;
+        }
+
+        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+        {
+            if (e.PropertyName == DropdownList.IsHorizontalProperty.PropertyName)
+            {
+                UpdateIsHorizontal();
+            }
+            else if (e.PropertyName == DropdownList.IsExpandedProperty.PropertyName)
+            {
+                UpdateIsExpanded();
+            }
+            else if (e.PropertyName == DropdownList.SelectedItemProperty.PropertyName)
+            {
+                UpdateText();
+            }
+            base.OnElementPropertyChanged(sender, e);
+        }
+
+        void UpdateIsHorizontal()
+        {
+            Control.IsHorizontal = Element.IsHorizontal;
+        }
+
+        void UpdateIsExpanded()
+        {
+            if (Element.IsExpanded)
+            {
+                Control.HoverBegin();
+            }
+            else
+            {
+                Control.HoverEnd();
+            }
+        }
+
+        void UpdateText()
+        {
+            Control.Text = Element.SelectedItem != null ? Element.SelectedItem.ToString() : string.Empty;
+        }
+
+        void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+        {
+            if (e.NewItems != null)
+            {
+                AddItems(e.NewItems);
+            }
+            if (e.OldItems != null)
+            {
+                RemoveItems(e.OldItems);
+            }
+            if (e.Action == NotifyCollectionChangedAction.Reset)
+            {
+                ClearItems();
+            }
+        }
+
+        void AddItems(IEnumerable items)
+        {
+            foreach (object item in items)
+            {
+                _items.Add(Control.AddItem(item.ToString()), item);
+            }
+        }
+
+        void RemoveItems(IEnumerable items)
+        {
+            foreach (object item in items)
+            {
+                var target = _items.Where(d => d.Value == item).ToList();
+                if (target.Count == 1)
+                {
+                    Element.SelectedItem = null;
+                }
+                _items.Remove(target[0].Key);
+                target[0].Key.Delete();
+            }
+        }
+
+        void ClearItems()
+        {
+            Control.Clear();
+            _items.Clear();
+
+            Element.SelectedItem = null;
+        }
+    }
+}
index 49f809b..189cdc6 100644 (file)
@@ -38,6 +38,7 @@
   <ItemGroup>\r
     <Compile Include="ColorPickerViewRenderer.cs" />\r
     <Compile Include="MediaViewRenderer.cs" />\r
+    <Compile Include="DropdownListRenderer.cs" />\r
     <Compile Include="BackgroundRenderer.cs" />\r
     <Compile Include="Cells\DoubleLabelCellRenderer.cs" />\r
     <Compile Include="Cells\GridViewCellRenderer.cs" />\r
@@ -79,4 +80,4 @@
     <_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)</_FullFrameworkReferenceAssemblyPaths>\r
     <AutoUnifyAssemblyReferences>true</AutoUnifyAssemblyReferences>\r
   </PropertyGroup>\r
-</Project>
+</Project>\r
diff --git a/Tizen.Xamarin.Forms.Extension/DropdownList.cs b/Tizen.Xamarin.Forms.Extension/DropdownList.cs
new file mode 100755 (executable)
index 0000000..d902e38
--- /dev/null
@@ -0,0 +1,163 @@
+using System;
+using System.Collections;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Reflection;
+using Xamarin.Forms;
+
+namespace Tizen.Xamarin.Forms.Extension
+{
+    public class DropdownList : View
+    {
+        public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create("SelectedItem", typeof(object), typeof(DropdownList), default(object), BindingMode.TwoWay, coerceValue: OnCoerceSelectedItem, propertyChanged: OnSelectedItemChanged);
+
+        public static readonly BindableProperty IsHorizontalProperty = BindableProperty.Create("IsHorizontal", typeof(bool), typeof(DropdownList), default(bool));
+
+        public static readonly BindableProperty IsExpandedProperty = BindableProperty.Create("IsExpanded", typeof(bool), typeof(DropdownList), default(bool));
+
+        public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(DropdownList), default(IEnumerable), propertyChanged: OnItemsSourceChanged);
+
+        public static readonly BindableProperty DisplayMemberPathProperty = BindableProperty.Create("DisplayMemberPath", typeof(string), typeof(DropdownList), default(string), propertyChanged: OnDisplayMemberPathChanged);
+
+        public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;
+
+        internal IEnumerable InternalItems => _items;
+
+        ObservableCollection<object> _items = new ObservableCollection<object>();
+
+        public DropdownList()
+        {
+        }
+
+        public object SelectedItem
+        {
+            get { return (object)GetValue(SelectedItemProperty); }
+            set { SetValue(SelectedItemProperty, value); }
+        }
+
+        public bool IsHorizontal
+        {
+            get { return (bool)GetValue(IsHorizontalProperty); }
+            set { SetValue(IsHorizontalProperty, value); }
+        }
+
+        public bool IsExpanded
+        {
+            get { return (bool)GetValue(IsExpandedProperty); }
+            set { SetValue(IsExpandedProperty, value); }
+        }
+
+        public IEnumerable ItemsSource
+        {
+            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
+            set { SetValue(ItemsSourceProperty, value); }
+        }
+
+        public string DisplayMemberPath
+        {
+            get { return (string)GetValue(DisplayMemberPathProperty); }
+            set { SetValue(DisplayMemberPathProperty, value); }
+        }
+
+        static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            ((DropdownList)bindable).OnItemsSourceChanged((IEnumerable)oldValue, (IEnumerable)newValue);
+        }
+
+        void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
+        {
+            var oldObservable = oldValue as INotifyCollectionChanged;
+            if (oldObservable != null)
+                oldObservable.CollectionChanged -= ItemsSourceCollectionChanged;
+
+            var newObservable = newValue as INotifyCollectionChanged;
+            if (newObservable != null)
+            {
+                newObservable.CollectionChanged += ItemsSourceCollectionChanged;
+            }
+
+            if (newValue != null)
+            {
+                ResetItems();
+            }
+            else
+            {
+                _items.Clear();
+            }
+        }
+
+        void ItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+        {
+            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)
+        {
+            foreach (object newItem in e.NewItems)
+                _items.Add(GetDisplayMember(newItem));
+        }
+
+        void RemoveItems(NotifyCollectionChangedEventArgs e)
+        {
+            int index = e.OldStartingIndex < _items.Count ? e.OldStartingIndex : _items.Count;
+            foreach (object _ in e.OldItems)
+                _items.RemoveAt(index--);
+        }
+
+        void ResetItems()
+        {
+            if (ItemsSource == null)
+                return;
+
+            _items.Clear();
+            foreach (object item in ItemsSource)
+                _items.Add(GetDisplayMember(item));
+        }
+
+        object GetDisplayMember(object item)
+        {
+            if (string.IsNullOrEmpty(DisplayMemberPath) || string.IsNullOrWhiteSpace(DisplayMemberPath))
+                return item.ToString();
+
+            PropertyInfo prop = item.GetType().GetRuntimeProperty(DisplayMemberPath);
+
+            if (prop == null)
+                return item.ToString();
+
+            return prop.GetValue(item);
+        }
+
+        static object OnCoerceSelectedItem(BindableObject bindable, object value)
+        {
+            var dropdownList = bindable as DropdownList;
+            if (!dropdownList._items.Contains(value))
+                return null;
+
+            return value;
+        }
+
+        static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            var dropdownList = bindable as DropdownList;
+            if (oldValue != newValue)
+                dropdownList.ItemSelected?.Invoke(bindable as DropdownList, new SelectedItemChangedEventArgs(newValue));
+        }
+
+        static void OnDisplayMemberPathChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            var dropdownList = bindable as DropdownList;
+            dropdownList.ResetItems();
+        }
+    }
+}
index 6f0b282..d4b6428 100644 (file)
@@ -75,6 +75,7 @@
     <Compile Include="LongTapGestureRecognizer.cs" />\r
     <Compile Include="LongTapUpdatedEventArgs.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
+    <Compile Include="DropdownList.cs" />\r
     <Compile Include="RadioButton.cs" />\r
     <Compile Include="SelectedEventArgs.cs" />\r
     <Compile Include="ReadOnlyListAdapter.cs" />\r