[DropdownList] Fix Updating SelectedItem Issue 16/121316/10
authorjh5.cho <jh5.cho@samsung.com>
Mon, 27 Mar 2017 13:54:46 +0000 (22:54 +0900)
committerjh5.cho <jh5.cho@samsung.com>
Fri, 21 Apr 2017 07:26:02 +0000 (16:26 +0900)
    - Update setting SelectedItem (as item object itself, not as string text)
    - Fix Updating Text when SelectedItem is set when it launches
    - Update items when member values in ItemsSource is changed

Change-Id: I8c2cea184214478fdaadf55eb1c10ba8c817fc30

Tizen.Xamarin.Forms.Extension.Renderer/DropdownListRenderer.cs
Tizen.Xamarin.Forms.Extension/DropdownList.cs [changed mode: 0644->0755]

index 94ecf0c..a57e9be 100755 (executable)
@@ -1,3 +1,4 @@
+using ElmSharp;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -5,28 +6,24 @@ using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Linq;
+using System.Reflection;
 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>
+    public class DropdownListRenderer : ViewRenderer<DropdownList, Hoversel>
     {
-        Dictionary<ElmSharp.HoverselItem, object> _items = new Dictionary<ElmSharp.HoverselItem, object>();
-
-        public DropdownListRenderer()
-        {
-        }
+        Dictionary<HoverselItem, object> _items = new Dictionary<HoverselItem, object>();
 
         protected override void OnElementChanged(ElementChangedEventArgs<DropdownList> e)
         {
             if (Control == null)
             {
-                var dropdownList = new EHoversel(TForms.Context.MainWindow);
+                var dropdownList = new Hoversel(TForms.Context.MainWindow);
                 SetNativeControl(dropdownList);
             }
             if (e.OldElement != null)
@@ -43,16 +40,16 @@ namespace Tizen.Xamarin.Forms.Extension.Renderer
 
                 Control.HoverParent = Platform.GetRenderer(Element.Parent)?.NativeView;
 
-                ClearItems();
                 AddItems(e.NewElement.InternalItems);
 
                 UpdateIsHorizontal();
                 UpdateIsExpanded();
+                UpdateText();
             }
             base.OnElementChanged(e);
         }
 
-        void ItemSelectedEventHandler(object sender, ElmSharp.HoverselItemEventArgs e)
+        void ItemSelectedEventHandler(object sender, HoverselItemEventArgs e)
         {
             Element.SelectedItem = _items[e.Item];
         }
@@ -62,6 +59,49 @@ namespace Tizen.Xamarin.Forms.Extension.Renderer
             Element.IsExpanded = false;
         }
 
+        bool IsPrimitive()
+        {
+            string displayMemberPath = Element.DisplayMemberPath;
+            if (string.IsNullOrEmpty(displayMemberPath) || string.IsNullOrWhiteSpace(displayMemberPath))
+            {
+                return true;
+            }
+            object itemsSourceObj = Element.ItemsSource.OfType<object>().FirstOrDefault();
+            var typeInfo = itemsSourceObj.GetType().GetTypeInfo();
+            if (typeInfo.IsVisible || typeInfo.IsPrimitive || typeInfo.IsValueType)
+            {
+                return true;
+            }
+            return false;
+        }
+
+        string GetDisplayMember(object item)
+        {
+            if(IsPrimitive())
+            {
+                return item.ToString();
+            }
+
+            var propertyPathParts = Element.DisplayMemberPath.Split('.');
+            object propertyValue = item;
+            foreach (var propertyPathPart in propertyPathParts)
+            {
+                var propInfo = propertyValue.GetType().GetTypeInfo().GetDeclaredProperty(propertyPathPart);
+                if (propInfo == null)
+                {
+                    // No Property was found
+                    return item.ToString();
+                }
+                propertyValue = propInfo.GetValue(propertyValue);
+            }
+            if (propertyValue == null)
+            {
+                // No Property was found
+                return item.ToString();
+            }
+            return propertyValue.ToString();
+        }
+
         protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
         {
             if (e.PropertyName == DropdownList.IsHorizontalProperty.PropertyName)
@@ -72,6 +112,10 @@ namespace Tizen.Xamarin.Forms.Extension.Renderer
             {
                 UpdateIsExpanded();
             }
+            else if (e.PropertyName == DropdownList.DisplayMemberPathProperty.PropertyName)
+            {
+                UpdateElementItems(_items);
+            }
             else if (e.PropertyName == DropdownList.SelectedItemProperty.PropertyName)
             {
                 UpdateText();
@@ -98,7 +142,7 @@ namespace Tizen.Xamarin.Forms.Extension.Renderer
 
         void UpdateText()
         {
-            Control.Text = Element.SelectedItem != null ? Element.SelectedItem.ToString() : string.Empty;
+            Control.Text = Element.SelectedItem != null ? GetDisplayMember(Element.SelectedItem) : string.Empty;
         }
 
         void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@@ -121,8 +165,30 @@ namespace Tizen.Xamarin.Forms.Extension.Renderer
         {
             foreach (object item in items)
             {
-                _items.Add(Control.AddItem(item.ToString()), item);
+                if (item is INotifyPropertyChanged)
+                {
+                    ((INotifyPropertyChanged)item).PropertyChanged -= OnItemPropertyChanged;
+                    ((INotifyPropertyChanged)item).PropertyChanged += OnItemPropertyChanged;
+                }
+                _items.Add(Control.AddItem(GetDisplayMember(item)), item);
+            }
+        }
+
+        private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
+        {
+            if (Element.DisplayMemberPath == e.PropertyName)
+            {
+                UpdateElementItems(_items.Where(p => p.Value == sender));
+            }
+        }
+
+        void UpdateElementItems(IEnumerable<KeyValuePair<HoverselItem, object>> items)
+        {
+            foreach (var target in items)
+            {
+                target.Key.SetPartText("default", GetDisplayMember(target.Value));
             }
+            UpdateText();
         }
 
         void RemoveItems(IEnumerable items)
@@ -130,9 +196,11 @@ namespace Tizen.Xamarin.Forms.Extension.Renderer
             foreach (object item in items)
             {
                 var target = _items.Where(d => d.Value == item).ToList();
-                if (target.Count == 1)
+                if (target.Count == 1 && (target[0].Value == Element.SelectedItem))
                 {
                     Element.SelectedItem = null;
+                    if (item is INotifyPropertyChanged)
+                        ((INotifyPropertyChanged)item).PropertyChanged -= OnItemPropertyChanged;
                 }
                 _items.Remove(target[0].Key);
                 target[0].Key.Delete();
old mode 100644 (file)
new mode 100755 (executable)
index 2571ea2..784cd4a
@@ -2,7 +2,6 @@ using System;
 using System.Collections;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
-using System.Reflection;
 using Xamarin.Forms;
 
 namespace Tizen.Xamarin.Forms.Extension
@@ -53,7 +52,7 @@ namespace Tizen.Xamarin.Forms.Extension
         /// <summary>
         /// BindableProperty. Identifies the DisplayMemberPath bindable property.
         /// </summary>
-        public static readonly BindableProperty DisplayMemberPathProperty = BindableProperty.Create("DisplayMemberPath", typeof(string), typeof(DropdownList), default(string), propertyChanged: OnDisplayMemberPathChanged);
+        public static readonly BindableProperty DisplayMemberPathProperty = BindableProperty.Create("DisplayMemberPath", typeof(string), typeof(DropdownList), default(string));
 
         /// <summary>
         /// Occurs when an item in the DropdownList is selected.
@@ -65,10 +64,6 @@ namespace Tizen.Xamarin.Forms.Extension
 
         ObservableCollection<object> _items = new ObservableCollection<object>();
 
-        public DropdownList()
-        {
-        }
-
         /// <summary>
         /// Gets or sets the currently selected item from the DropdownList.ItemsSource.
         /// </summary>
@@ -163,7 +158,7 @@ namespace Tizen.Xamarin.Forms.Extension
         void AddItems(NotifyCollectionChangedEventArgs e)
         {
             foreach (object newItem in e.NewItems)
-                _items.Add(GetDisplayMember(newItem));
+                _items.Add(newItem);
         }
 
         void RemoveItems(NotifyCollectionChangedEventArgs e)
@@ -180,20 +175,7 @@ namespace Tizen.Xamarin.Forms.Extension
 
             _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);
+                _items.Add(item);
         }
 
         static object OnCoerceSelectedItem(BindableObject bindable, object value)
@@ -207,15 +189,8 @@ namespace Tizen.Xamarin.Forms.Extension
 
         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();
+            var dropdownList = (DropdownList)bindable;
+            dropdownList.ItemSelected?.Invoke(bindable, new SelectedItemChangedEventArgs(newValue));
         }
     }
-}
\ No newline at end of file
+}