[NUI] use proper constructor of ArgumentNullException (#1708)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / DropDown.cs
1 /*
2  * Copyright(c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.Collections.Generic;
19 using Tizen.NUI.BaseComponents;
20 using System.ComponentModel;
21 using Tizen.NUI.Binding;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// DropDown is one kind of common component, a dropdown allows the user click dropdown button to choose one value from a list.
27     /// </summary>
28     /// <since_tizen> 6 </since_tizen>
29     /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
30     [EditorBrowsable(EditorBrowsableState.Never)]
31     public partial class DropDown : Control
32     {
33         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
34         [EditorBrowsable(EditorBrowsableState.Never)]
35         public static readonly BindableProperty ListPaddingProperty = BindableProperty.Create(nameof(ListPadding), typeof(Extents), typeof(DropDown), null, propertyChanged: (bindable, oldValue, newValue) =>
36         {
37             var instance = (DropDown)bindable;
38             if (newValue != null)
39             {
40                 instance.listPadding.CopyFrom((Extents)newValue);
41                 instance.UpdateDropDown();
42             }
43         },
44         defaultValueCreator: (bindable) =>
45         {
46             var instance = (DropDown)bindable;
47             return instance.listPadding;
48         });
49         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
50         [EditorBrowsable(EditorBrowsableState.Never)]
51         public static readonly BindableProperty SelectedItemIndexProperty = BindableProperty.Create(nameof(SelectedItemIndex), typeof(int), typeof(DropDown), 0, propertyChanged: (bindable, oldValue, newValue) =>
52         {
53             var instance = (DropDown)bindable;
54             if (newValue != null)
55             {
56                 int selectedItemIndex = (int)newValue;
57                 if (selectedItemIndex == instance.selectedItemIndex || instance.adapter == null || selectedItemIndex < 0 || selectedItemIndex >= instance.adapter.GetItemCount())
58                 {
59                     return;
60                 }
61                 instance.SetListItemToSelected((uint)selectedItemIndex);
62             }
63         },
64         defaultValueCreator: (bindable) =>
65         {
66             var instance = (DropDown)bindable;
67             return instance.selectedItemIndex;
68         });
69         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
70         [EditorBrowsable(EditorBrowsableState.Never)]
71         public static readonly BindableProperty ListMarginProperty = BindableProperty.Create(nameof(ListMargin), typeof(Extents), typeof(DropDown), null, propertyChanged: (bindable, oldValue, newValue) =>
72         {
73             var instance = (DropDown)bindable;
74             if (newValue != null)
75             {
76                 instance.listMargin.CopyFrom((Extents)newValue);
77                 instance.UpdateDropDown();
78             }
79         },
80         defaultValueCreator: (bindable) =>
81         {
82             var instance = (DropDown)bindable;
83             return instance.listMargin;
84         });
85         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
86         [EditorBrowsable(EditorBrowsableState.Never)]
87         public static readonly BindableProperty ListRelativeOrientationProperty = BindableProperty.Create(nameof(ListRelativeOrientation), typeof(ListOrientation), typeof(DropDown), ListOrientation.Left, propertyChanged: (bindable, oldValue, newValue) =>
88         {
89             var instance = (DropDown)bindable;
90             if (newValue != null)
91             {
92                 instance.listRelativeOrientation = (ListOrientation)newValue;
93                 instance.UpdateDropDown();
94             }
95         },
96         defaultValueCreator: (bindable) =>
97         {
98             var instance = (DropDown)bindable;
99             return instance.listRelativeOrientation;
100         });
101         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
102         [EditorBrowsable(EditorBrowsableState.Never)]
103         public static readonly BindableProperty SpaceBetweenButtonTextAndIconProperty = BindableProperty.Create(nameof(SpaceBetweenButtonTextAndIcon), typeof(int), typeof(DropDown), 0, propertyChanged: (bindable, oldValue, newValue) =>
104         {
105             var instance = (DropDown)bindable;
106             if (newValue != null)
107             {
108                 instance.spaceBetweenButtonTextAndIcon = (int)newValue;
109             }
110         },
111         defaultValueCreator: (bindable) =>
112         {
113             var instance = (DropDown)bindable;
114             return instance.spaceBetweenButtonTextAndIcon;
115         });
116
117         #region DropDown
118         private Button button = null;
119         private TextLabel headerText = null;
120         private TextLabel buttonText = null;
121         private ImageView listBackgroundImage = null;
122         // Component that scrolls the child added to it.
123         private ScrollableBase scrollableBase = null;
124
125         // The LinearLayout container to house the items in the drop down list.
126         private View dropDownMenuFullList = null;
127         private DropDownListBridge adapter = new DropDownListBridge();
128         private DropDownItemView selectedItemView = null;
129         private TapGestureDetector tapGestureDetector = null;
130
131         private Extents listMargin = new Extents(0, 0, 0, 0);
132         private Extents listPadding = new Extents(0, 0, 0, 0);
133         private ListOrientation listRelativeOrientation = ListOrientation.Left;
134         private int selectedItemIndex = -1;
135         private int spaceBetweenButtonTextAndIcon = 0;
136         private bool itemPressed = false;
137
138         static DropDown() { }
139
140         /// <summary>
141         /// Creates a new instance of a DropDown.
142         /// </summary>
143         /// <since_tizen> 6 </since_tizen>
144         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
145         [EditorBrowsable(EditorBrowsableState.Never)]
146         public DropDown() : base() { }
147
148         /// <summary>
149         /// Creates a new instance of a DropDown with style.
150         /// </summary>
151         /// <param name="style">Create DropDown by special style defined in UX.</param>
152         /// <since_tizen> 6 </since_tizen>
153         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
154         [EditorBrowsable(EditorBrowsableState.Never)]
155         public DropDown(string style) : base(style) { }
156
157         /// <summary>
158         /// Creates a new instance of a DropDown with style.
159         /// </summary>
160         /// <param name="dropDownStyle">Create DropDown by style customized by user.</param>
161         /// <since_tizen> 6 </since_tizen>
162         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
163         [EditorBrowsable(EditorBrowsableState.Never)]
164         public DropDown(DropDownStyle dropDownStyle) : base(dropDownStyle)
165         {
166         }
167
168         /// <summary>
169         /// An event for the item clicked signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
170         /// </summary>
171         /// <since_tizen> 6 </since_tizen>
172         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
173         [EditorBrowsable(EditorBrowsableState.Never)]
174         public event EventHandler<ItemClickEventArgs> ItemClickEvent;
175
176         /// <summary>
177         /// List position in relation to the main button.
178         /// </summary>
179         /// <since_tizen> 6 </since_tizen>
180         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
181         [EditorBrowsable(EditorBrowsableState.Never)]
182         public enum ListOrientation
183         {
184             /// <summary>
185             /// Left.
186             /// </summary>
187             /// <since_tizen> 6 </since_tizen>
188             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
189             [EditorBrowsable(EditorBrowsableState.Never)]
190             Left,
191             /// <summary>
192             /// Right.
193             /// </summary>
194             /// <since_tizen> 6 </since_tizen>
195             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
196             [EditorBrowsable(EditorBrowsableState.Never)]
197             Right,
198         }
199
200         /// <summary>
201         /// Get or set header text.
202         /// </summary>
203         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
204         [EditorBrowsable(EditorBrowsableState.Never)]
205         public TextLabel HeaderText
206         {
207             get
208             {
209                 if (null == headerText)
210                 {
211                     headerText = new TextLabel()
212                     {
213                         WidthResizePolicy = ResizePolicyType.UseNaturalSize,
214                         HeightResizePolicy = ResizePolicyType.UseNaturalSize,
215                         HorizontalAlignment = HorizontalAlignment.Center,
216                         VerticalAlignment = VerticalAlignment.Center,
217                         ParentOrigin = NUI.ParentOrigin.Center,
218                         PivotPoint = NUI.ParentOrigin.Center,
219                         PositionUsesPivotPoint = true,
220                         Name = "DropDownHeaderText"
221                     };
222                     Add(headerText);
223                 }
224                 return headerText;
225             }
226             internal set
227             {
228                 headerText = value;
229             }
230         }
231
232         /// <summary>
233         /// Get or set button.
234         /// </summary>
235         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
236         [EditorBrowsable(EditorBrowsableState.Never)]
237         public Button Button
238         {
239             get
240             {
241                 if (null == button)
242                 {
243                     button = new Button()
244                     {
245                         ParentOrigin = NUI.ParentOrigin.CenterLeft,
246                         PivotPoint = NUI.PivotPoint.CenterLeft,
247                         PositionUsesPivotPoint = true,
248                         HeightResizePolicy = ResizePolicyType.FitToChildren,
249                         IconRelativeOrientation = Button.IconOrientation.Right,
250                         Name = "DropDownButton"
251                     };
252                     button.ClickEvent += ButtonClickEvent;
253                     Add(button);
254
255                     if (null == buttonText)
256                     {
257                         buttonText = new TextLabel();
258                     }
259                 }
260                 return button;
261             }
262             internal set
263             {
264                 button = value;
265             }
266         }
267
268         /// <summary>
269         /// Get or set the background image of list.
270         /// </summary>
271         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
272         [EditorBrowsable(EditorBrowsableState.Never)]
273         public ImageView ListBackgroundImage
274         {
275             get
276             {
277                 if (null == listBackgroundImage)
278                 {
279                     listBackgroundImage = new ImageView()
280                     {
281                         Name = "ListBackgroundImage",
282                         PositionUsesPivotPoint = true,
283                         ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft,
284                         PivotPoint = Tizen.NUI.PivotPoint.TopLeft,
285                         WidthResizePolicy = ResizePolicyType.FitToChildren,
286                         HeightResizePolicy = ResizePolicyType.FitToChildren,
287                     };
288                     Add(listBackgroundImage);
289
290                     if (null == scrollableBase) // scrollableBase used to test of ListContainer Setup invoked already
291                     {
292                         SetUpListContainer();
293                     }
294                 }
295                 return listBackgroundImage;
296             }
297             internal set
298             {
299                 listBackgroundImage = value;
300             }
301         }
302
303         /// <summary>
304         /// Return a copied Style instance of DropDown
305         /// </summary>
306         /// <remarks>
307         /// It returns copied Style instance and changing it does not effect to the DropDown.
308         /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
309         /// </remarks>
310         /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
311         [EditorBrowsable(EditorBrowsableState.Never)]
312         //public new DropDownStyle Style
313         //{
314         //    get
315         //    {
316         //        return new DropDownStyle(ViewStyle as DropDownStyle);
317         //    }
318         //}
319         public new DropDownStyle Style => ViewStyle as DropDownStyle;
320
321         /// <summary>
322         /// Space between button text and button icon in DropDown.
323         /// </summary>
324         /// <since_tizen> 6 </since_tizen>
325         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
326         public int SpaceBetweenButtonTextAndIcon
327         {
328             get => (int)GetValue(SpaceBetweenButtonTextAndIconProperty);
329             set => SetValue(SpaceBetweenButtonTextAndIconProperty, value);
330         }
331
332         /// <summary>
333         /// List relative orientation in DropDown.
334         /// </summary>
335         /// <since_tizen> 6 </since_tizen>
336         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
337         public ListOrientation ListRelativeOrientation
338         {
339             get => (ListOrientation)GetValue(ListRelativeOrientationProperty);
340             set => SetValue(ListRelativeOrientationProperty, value);
341         }
342
343         /// <summary>
344         /// Space in list.
345         /// </summary>
346         /// <since_tizen> 6 </since_tizen>
347         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
348         public Extents ListMargin
349         {
350             get
351             {
352                 Extents tmp = (Extents)GetValue(ListMarginProperty);
353                 return new Extents((ushort start, ushort end, ushort top, ushort bottom) => { ListMargin = new Extents(start, end, top, bottom); }, tmp.Start, tmp.End, tmp.Top, tmp.Bottom);
354             }
355             set => SetValue(ListMarginProperty, value);
356         }
357
358         /// <summary>
359         /// Selected item index in list.
360         /// </summary>
361         /// <since_tizen> 6 </since_tizen>
362         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
363         public int SelectedItemIndex
364         {
365             get => (int)GetValue(SelectedItemIndexProperty);
366             set => SetValue(SelectedItemIndexProperty, value);
367         }
368
369         /// <summary>
370         /// List padding in DropDown.
371         /// </summary>
372         /// <since_tizen> 6 </since_tizen>
373         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
374         public Extents ListPadding
375         {
376             get
377             {
378                 Extents tmp = (Extents)GetValue(ListPaddingProperty);
379                 return new Extents((ushort start, ushort end, ushort top, ushort bottom) => { ListPadding = new Extents(start, end, top, bottom); }, tmp.Start, tmp.End, tmp.Top, tmp.Bottom);
380             }
381             set => SetValue(ListPaddingProperty, value);
382         }
383
384         /// <summary>
385         /// Add list item by item data. The added item will be added to end of all items automatically.
386         /// </summary>
387         /// <param name="itemData">Item data which will apply to tab item view.</param>
388         /// <since_tizen> 6 </since_tizen>
389         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
390         [EditorBrowsable(EditorBrowsableState.Never)]
391         public void AddItem(DropDownDataItem itemData)
392         {
393            // Add item to adaptor, will be added to list via AddItemAt during OnUpdate()
394            int insertionPosition = adapter.GetItemCount();
395            adapter.InsertData(insertionPosition, itemData);
396         }
397
398         /// <summary>
399         /// Delete list item by index.
400         /// </summary>
401         /// <param name="index">Position index where will be deleted.</param>
402         /// <since_tizen> 6 </since_tizen>
403         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
404         [EditorBrowsable(EditorBrowsableState.Never)]
405         public void DeleteItem(int index)
406         {
407             if (index < 0 || index >= adapter?.GetItemCount()) return;
408             if (null == dropDownMenuFullList) return;
409
410             if (selectedItemIndex == index)
411             {
412                 selectedItemIndex = -1;
413             }
414             else if(selectedItemIndex > index)
415             {
416                 selectedItemIndex--;
417             }
418
419             adapter?.RemoveData(index);
420
421             if(index < dropDownMenuFullList.ChildCount)
422             {
423                 View childToRemove = dropDownMenuFullList.GetChildAt((uint)index);
424                 if (childToRemove)
425                 {
426                     childToRemove.TouchEvent -= ListItemTouchEvent;
427                     dropDownMenuFullList.Remove(childToRemove);
428                     dropDownMenuFullList?.Layout?.RequestLayout();
429                 }
430             }
431         }
432
433         /// <summary>
434         /// Insert list item by item data. The inserted item will be added to the special position by index automatically.
435         /// </summary>
436         /// <param name="item">Item data which will apply to tab item view.</param>
437         /// <param name="index">Position index where will be inserted.</param>
438         /// <since_tizen> 6 </since_tizen>
439         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
440         [EditorBrowsable(EditorBrowsableState.Never)]
441         public void InsertItem(DropDownDataItem item, int index)
442         {
443             if (index < 0 || index >= adapter.GetItemCount())
444             {
445                 return;
446             }
447
448             if (selectedItemIndex >= index)
449             {
450                 selectedItemIndex++;
451             }
452
453             adapter.InsertData(index, item);
454         }
455
456         /// <summary>
457         /// Add scroll bar to list.
458         /// </summary>
459         /// <param name="scrollBar">Scroll bar defined by user which will be added to list.</param>
460         /// <since_tizen> 6 </since_tizen>
461         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
462         [EditorBrowsable(EditorBrowsableState.Never)]
463         public void AttachScrollBar(ScrollBar scrollBar)
464         {
465             if (scrollableBase == null)
466             {
467                 return;
468             }
469             Tizen.Log.Error("DropDown","Feature unsupported");
470         }
471
472         /// <summary>
473         /// Detach scroll bar to list.
474         /// </summary>
475         /// <since_tizen> 6 </since_tizen>
476         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
477         [EditorBrowsable(EditorBrowsableState.Never)]
478         public void DetachScrollBar()
479         {
480             if (scrollableBase == null)
481             {
482                 return;
483             }
484             Tizen.Log.Error("DropDown","Feature unsupported");
485         }
486
487         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
488         [EditorBrowsable(EditorBrowsableState.Never)]
489         public override void ApplyStyle(ViewStyle viewStyle)
490         {
491             base.ApplyStyle(viewStyle);
492
493             DropDownStyle dropDownStyle = viewStyle as DropDownStyle;
494             if (null != dropDownStyle)
495             {
496                 if (null != dropDownStyle.Button)
497                 {
498                     Button.ApplyStyle(dropDownStyle.Button);
499                 }
500                 if (null != dropDownStyle.HeaderText)
501                 {
502                     HeaderText.ApplyStyle(dropDownStyle.HeaderText);
503                 }
504                 if (null != dropDownStyle.ListBackgroundImage)
505                 {
506                     ListBackgroundImage.ApplyStyle(dropDownStyle.ListBackgroundImage);
507                 }
508                 UpdateDropDown();
509             }
510         }
511
512         /// <summary>
513         /// Update DropDown by style.
514         /// </summary>
515         /// <since_tizen> 6 </since_tizen>
516         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
517         [EditorBrowsable(EditorBrowsableState.Never)]
518         protected void UpdateDropDown()
519         {
520             if (null == scrollableBase || null == listBackgroundImage || null == dropDownMenuFullList) return;
521             if (null == Style.ListBackgroundImage.Size) return;
522             // Resize and position scrolling list within the drop down list container.  Can be used to position list in relation to the background image.
523             scrollableBase.Size = Style.ListBackgroundImage.Size - new Size((listPadding.Start + listPadding.End), (listPadding.Top + listPadding.Bottom), 0);
524             scrollableBase.Position2D = new Position2D(listPadding.Start, listPadding.Top);
525
526             int listBackgroundImageX = 0;
527             int listBackgroundImageY = 0;
528             if (listRelativeOrientation == ListOrientation.Left)
529             {
530                 listBackgroundImageX = (int)listMargin.Start;
531                 listBackgroundImageY = (int)listMargin.Top;
532             }
533             else if (listRelativeOrientation == ListOrientation.Right)
534             {
535                 listBackgroundImageX = -(int)listMargin.End;
536                 listBackgroundImageY = (int)listMargin.Top;
537             }
538             listBackgroundImage.Position2D = new Position2D(listBackgroundImageX, listBackgroundImageY);
539             dropDownMenuFullList?.Layout?.RequestLayout();
540         }
541
542         /// <summary>
543         /// update.
544         /// </summary>
545         protected override void OnUpdate()
546         {
547             float buttonTextWidth = 0;
548             if (null != buttonText)
549             {
550                 buttonText.Text = Style.Button.Text.Text.All;
551                 buttonText.PointSize = Style.Button.Text.PointSize?.GetValue(ControlState) ?? StyleManager.PointSizeNormal;
552                 buttonTextWidth = buttonText.NaturalSize.Width;
553             }
554             float fitWidth = (Style.Button.Icon.Size?.Width ?? 48) + Style.SpaceBetweenButtonTextAndIcon + buttonTextWidth;
555             fitWidth += (button.IconPadding.Start + button.IconPadding.End);
556             button.Size.Width = Math.Max(button.Size.Width, fitWidth);
557             RelayoutRequest();
558
559             int numberOfItemsToAdd = adapter.GetItemCount();
560
561             if (adapter.AdapterPurge == true)
562             {
563                 adapter.AdapterPurge = false;
564                 for (int i = 0; i < numberOfItemsToAdd; i++)
565                 {
566                     AddItemAt(adapter.GetData(i), i);
567                 }
568             }
569             // Set selection icon on View
570             if (selectedItemIndex > 0)
571             {
572                 SetListItemToSelected((uint)selectedItemIndex, selectedItemView);
573             }
574         }
575
576         /// <summary>
577         /// Dispose DropDown and all children on it.
578         /// </summary>
579         /// <param name="type">Dispose type.</param>
580         /// <since_tizen> 6 </since_tizen>
581         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
582         [EditorBrowsable(EditorBrowsableState.Never)]
583         protected override void Dispose(DisposeTypes type)
584         {
585             if (disposed)
586             {
587                 return;
588             }
589
590             if (type == DisposeTypes.Explicit)
591             {
592                 Utility.Dispose(headerText);
593                 Utility.Dispose(buttonText);
594                 Utility.Dispose(button);
595                 Utility.Dispose(scrollableBase);
596                 Utility.Dispose(dropDownMenuFullList);
597                 Utility.Dispose(listBackgroundImage);
598             }
599
600             base.Dispose(type);
601         }
602
603         /// <summary>
604         /// Get DropDown style.
605         /// </summary>
606         /// <returns>The default dropdown style.</returns>
607         /// <since_tizen> 6 </since_tizen>
608         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
609         [EditorBrowsable(EditorBrowsableState.Never)]
610         protected override ViewStyle CreateViewStyle()
611         {
612             return new DropDownStyle();
613         }
614
615         private void AddItemAt(DropDownDataItem itemData,int index)
616         {
617             ViewHolder viewHolder = adapter.OnCreateViewHolder();
618             if (!viewHolder.IsBound)
619             {
620                 adapter.BindViewHolder(viewHolder, index);
621                 viewHolder.IsBound = true;
622             }
623
624             if (tapGestureDetector == null)
625             {
626                 tapGestureDetector = new TapGestureDetector();
627             }
628             View view = viewHolder.ItemView;
629             view.ApplyStyle(itemData.itemDataStyle);
630             view.TouchEvent += ListItemTouchEvent;
631             dropDownMenuFullList.Add(view);
632         }
633
634         private void OnClickEvent(object sender, ItemClickEventArgs e)
635         {
636             ItemClickEvent?.Invoke(sender, e);
637         }
638
639         private void CreateButtonText()
640         {
641             if (null == buttonText)
642             {
643                 buttonText = new TextLabel();
644             }
645         }
646
647         private void CreateButton()
648         {
649             if (null == button)
650             {
651                 button = new Button()
652                 {
653                     ParentOrigin = NUI.ParentOrigin.CenterLeft,
654                     PivotPoint = NUI.PivotPoint.CenterLeft,
655                     PositionUsesPivotPoint = true,
656                     HeightResizePolicy = ResizePolicyType.FitToChildren,
657                     IconRelativeOrientation = Button.IconOrientation.Right,
658                 };
659                 button.Name = "DropDownButton";
660                 button.ClickEvent += ButtonClickEvent;
661                 Add(button);
662             }
663         }
664
665         private void SetUpListContainer()
666         {
667             LinearLayout linear = new LinearLayout()
668             {
669                 LinearOrientation = LinearLayout.Orientation.Vertical,
670             };
671
672             dropDownMenuFullList = new View()
673             {
674                 Layout = linear,
675                 Name = "DropDownMenuList",
676                 WidthSpecification = LayoutParamPolicies.MatchParent,
677                 HeightSpecification = LayoutParamPolicies.WrapContent,
678                 Focusable = true,
679             };
680
681             scrollableBase = new ScrollableBase()
682             {
683                 Name = "Scrollable",
684             };
685             scrollableBase.Add(dropDownMenuFullList);
686
687             listBackgroundImage.Add(scrollableBase);
688             listBackgroundImage.Hide();
689         }
690
691         private View GetViewFromIndex(uint index)
692         {
693             if ((index < dropDownMenuFullList.ChildCount) && (index >=0) )
694             {
695                 return dropDownMenuFullList.GetChildAt(index);
696             }
697             else
698             {
699                 return null;
700             }
701         }
702
703         private void SetListItemToSelected(DropDownItemView view)
704         {
705             if (dropDownMenuFullList == null || view == null || view == selectedItemView)
706             {
707                 return;
708             }
709
710             uint newSelectedIndex = 0;
711             for (; newSelectedIndex < dropDownMenuFullList.ChildCount; newSelectedIndex++)
712             {
713                 var itemView = dropDownMenuFullList.GetChildAt(newSelectedIndex) as DropDownItemView;
714                 if (itemView == view)
715                 {
716                     SetListItemToSelected(newSelectedIndex, view);
717                     return;
718                 }
719             }
720         }
721
722         private void SetListItemToSelected(uint index)
723         {
724             if (dropDownMenuFullList == null || index == selectedItemIndex)
725             {
726                 return;
727             }
728
729             SetListItemToSelected(index, GetViewFromIndex(index) as DropDownItemView);
730         }
731
732         private void SetListItemToSelected(uint index, DropDownItemView view)
733         {
734             if (adapter == null)
735             {
736                 return;
737             }
738
739             if (selectedItemView != null)
740             {
741                 selectedItemView.IsSelected = false;
742                 selectedItemView.ControlState = ControlStates.Normal;
743                 adapter.GetData(selectedItemIndex).IsSelected = false;
744             }
745
746             if (view == null || index >= dropDownMenuFullList.ChildCount)
747             {
748                 selectedItemIndex = -1;
749                 selectedItemView = null;
750                 return;
751             }
752
753             selectedItemIndex = (int)index;
754             selectedItemView = view;
755             selectedItemView.ControlState = ControlStates.Selected;
756             selectedItemView.IsSelected = true;
757             adapter.GetData(selectedItemIndex).IsSelected = true;
758             dropDownMenuFullList.Layout?.RequestLayout();
759         }
760
761         private bool ListItemTouchEvent(object sender, TouchEventArgs e)
762         {
763             PointStateType state = e.Touch.GetState(0);
764             DropDownItemView touchedView = sender as DropDownItemView;;
765             switch (state)
766             {
767                 case PointStateType.Down:
768                     if (touchedView != null)
769                     {
770                         touchedView.ControlState = ControlStates.Pressed;
771                     }
772                     itemPressed = true;  // if matched with a Up then a click event.
773                     break;
774                 case PointStateType.Motion:
775                     if (touchedView != null)
776                     {
777                         touchedView.ControlState = ControlStates.Normal;
778                     }
779                     itemPressed = false;
780                     break;
781                 case PointStateType.Up:
782                     if (touchedView != null)
783                     {
784                         if (itemPressed)  // if Down was previously sent without motion (Scrolling) in-between then a clicked event occurred.
785                         {
786                             // List item clicked
787                             Console.WriteLine("Tapped{0}", touchedView.Name);
788                             SetListItemToSelected(touchedView);
789                             button.Text = touchedView.Text;
790                             button.Show();
791                             listBackgroundImage.Hide();
792                         }
793                     }
794                     break;
795                 default:
796                     break;
797             }
798             return true;
799         }
800
801         private void ButtonClickEvent(object sender, Button.ClickEventArgs e)
802         {
803             button.Hide();
804             listBackgroundImage.Show();
805             dropDownMenuFullList?.Layout?.RequestLayout();
806             listBackgroundImage.RaiseToTop();
807         }
808
809         #endregion
810
811         #region ItemClickEventArgs
812         /// <summary>
813         /// ItemClickEventArgs is a class to record item click event arguments which will sent to user.
814         /// </summary>
815         /// <since_tizen> 6 </since_tizen>
816         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
817         [EditorBrowsable(EditorBrowsableState.Never)]
818         public class ItemClickEventArgs : EventArgs
819         {
820             /// <summary> Clicked item index of DropDown's list </summary>
821             /// <since_tizen> 6 </since_tizen>
822             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
823             [EditorBrowsable(EditorBrowsableState.Never)]
824             public int Index { get; set; }
825             /// <summary> Clicked item text string of DropDown's list </summary>
826             /// <since_tizen> 6 </since_tizen>
827             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
828             [EditorBrowsable(EditorBrowsableState.Never)]
829             public string Text { get; set; }
830         }
831         #endregion
832
833         #region ViewHolder
834
835         /// <summary>
836         /// A ViewHolder is a class that holds a View created from DropDownListBridge data.
837         /// </summary>
838         /// <since_tizen> 6 </since_tizen>
839         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
840         [EditorBrowsable(EditorBrowsableState.Never)]
841         public class ViewHolder
842         {
843             /// <summary>
844             /// ViewHolder constructor.
845             /// </summary>
846             /// <param name="itemView">View</param>
847             /// <since_tizen> 6 </since_tizen>
848             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
849             [EditorBrowsable(EditorBrowsableState.Never)]
850             public ViewHolder(View itemView)
851             {
852                 ItemView = itemView ?? throw new ArgumentNullException(nameof(itemView), "itemView may not be null");
853             }
854
855             /// <summary>
856             /// Returns the view.
857             /// </summary>
858             /// <since_tizen> 6 </since_tizen>
859             /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
860             [EditorBrowsable(EditorBrowsableState.Never)]
861             public View ItemView { get; }
862
863             internal bool IsBound { get; set; }
864         }
865
866         #endregion
867     }
868 }