Follow formatting NUI
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / BindableObject.cs
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Diagnostics;
5 using System.Reflection;
6 using System.Runtime.CompilerServices;
7 using Tizen.NUI.Binding.Internals;
8
9 namespace Tizen.NUI.Binding
10 {
11     /// <summary>
12     /// Provides a mechanism by which application developers can propagate changes that are made to data in one object to another, by enabling validation, type coercion, and an event system.
13     /// </summary>
14     [EditorBrowsable(EditorBrowsableState.Never)]
15     public abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
16     {
17         /// <summary>
18         /// Implements the bound property whose interface is provided by the BindingContext property.
19         /// </summary>
20         [EditorBrowsable(EditorBrowsableState.Never)]
21         public static readonly BindableProperty BindingContextProperty =
22             BindableProperty.Create(nameof(BindingContext), typeof(object), typeof(BindableObject), default(object),
23                                     BindingMode.OneWay, null, BindingContextPropertyChanged, null, null, BindingContextPropertyBindingChanging);
24
25         readonly List<BindablePropertyContext> _properties = new List<BindablePropertyContext>(4);
26
27         bool _applying;
28         object _inheritedContext;
29
30         /// <summary>
31         /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
32         /// </summary>
33         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
34         [EditorBrowsable(EditorBrowsableState.Never)]
35         public object BindingContext
36         {
37             get { return _inheritedContext ?? GetValue(BindingContextProperty); }
38             set { SetValue(BindingContextProperty, value); }
39         }
40
41         void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
42         {
43             SetDynamicResource(property, key, false);
44         }
45
46         /// <summary>
47         /// Raised when a property has changed.
48         /// </summary>
49         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
50         [EditorBrowsable(EditorBrowsableState.Never)]
51         public event PropertyChangedEventHandler PropertyChanged;
52
53         /// <summary>Whether to allow null value when <seealso cref="CopyFrom"/>.</summary>
54         [EditorBrowsable(EditorBrowsableState.Never)]
55         protected static bool AllowNullCopy { get; set; } = false;
56
57         /// <summary>Copy properties of other ViewStyle to this.</summary>
58         /// <param name="other">The other BindableProperty merge to this.</param>
59         [EditorBrowsable(EditorBrowsableState.Never)]
60         public virtual void CopyFrom(BindableObject other)
61         {
62             if (null == other) return;
63
64             Type type1 = this.GetType();
65             BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
66
67             Type type2 = other.GetType();
68             BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
69
70             if (null != nameToBindableProperty1)
71             {
72                 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
73                 {
74                     nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
75
76                     if (null != bindableProperty)
77                     {
78                         object value = other.GetValue(bindableProperty);
79
80                         if (AllowNullCopy || null != value)
81                         {
82                             SetValue(keyValuePair.Value, value);
83                         }
84                     }
85                 }
86             }
87         }
88
89         /// <summary>
90         /// Raised whenever the BindingContext property changes.
91         /// </summary>
92         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
93         [EditorBrowsable(EditorBrowsableState.Never)]
94         public event EventHandler BindingContextChanged;
95
96         internal void ClearValue(BindableProperty property, bool fromStyle)
97         {
98             ClearValue(property, fromStyle: fromStyle, checkAccess: true);
99         }
100
101         /// <summary>
102         /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
103         /// </summary>
104         /// <param name="property">The BindableProperty to clear</param>
105         internal void ClearValue(BindableProperty property)
106         {
107             ClearValue(property, fromStyle: false, checkAccess: true);
108         }
109
110         /// <summary>
111         /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
112         /// </summary>
113         /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
114         internal void ClearValue(BindablePropertyKey propertyKey)
115         {
116             if (propertyKey == null)
117                 throw new ArgumentNullException(nameof(propertyKey));
118
119             ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
120         }
121
122         /// <summary>
123         /// Return true if the target property exists and has been set.
124         /// </summary>
125         /// <param name="targetProperty">The target property</param>
126         /// <returns>return true if the target property exists and has been set</returns>
127         internal bool IsSet(BindableProperty targetProperty)
128         {
129             if (targetProperty == null)
130                 throw new ArgumentNullException(nameof(targetProperty));
131
132             var bpcontext = GetContext(targetProperty);
133             return bpcontext != null
134                 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
135         }
136
137         /// <summary>
138         /// Returns the value that is contained the BindableProperty.
139         /// </summary>
140         /// <param name="property">The BindableProperty for which to get the value.</param>
141         /// <returns>The value that is contained the BindableProperty</returns>
142         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
143         [EditorBrowsable(EditorBrowsableState.Never)]
144         public object GetValue(BindableProperty property)
145         {
146             if (property == null)
147                 throw new ArgumentNullException(nameof(property));
148
149             BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
150
151             if (context == null)
152                 return property.DefaultValue;
153
154             return context.Value;
155         }
156
157         /// <summary>
158         /// Raised when a property is about to change.
159         /// </summary>
160         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
161         [EditorBrowsable(EditorBrowsableState.Never)]
162         public event PropertyChangingEventHandler PropertyChanging;
163
164         /// <summary>
165         /// Removes a previously set binding.
166         /// </summary>
167         /// <param name="property">The BindableProperty from which to remove bindings.</param>
168         internal void RemoveBinding(BindableProperty property)
169         {
170             if (property == null)
171                 throw new ArgumentNullException(nameof(property));
172
173             BindablePropertyContext context = GetContext(property);
174             if (context == null || context.Binding == null)
175                 return;
176
177             RemoveBinding(property, context);
178         }
179
180         /// <summary>
181         /// Assigns a binding to a property.
182         /// </summary>
183         /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
184         /// <param name="binding">The binding to set.</param>
185         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
186         [EditorBrowsable(EditorBrowsableState.Never)]
187         public void SetBinding(BindableProperty targetProperty, BindingBase binding)
188         {
189             SetBinding(targetProperty, binding, false);
190         }
191
192         private bool isCreateByXaml = false;
193         /// Only used by the IL of xaml, will never changed to not hidden.
194         [EditorBrowsable(EditorBrowsableState.Never)]
195         public virtual bool IsCreateByXaml
196         {
197             get
198             {
199                 return isCreateByXaml;
200             }
201             set
202             {
203                 isCreateByXaml = value;
204             }
205         }
206
207         /// <summary>
208         /// Sets the value of the specified property.
209         /// </summary>
210         /// <param name="property">The BindableProperty on which to assign a value.</param>
211         /// <param name="value">The value to set.</param>
212         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
213         [EditorBrowsable(EditorBrowsableState.Never)]
214         public void SetValue(BindableProperty property, object value)
215         {
216             if (true == isCreateByXaml)
217             {
218                 SetValue(property, value, false, true);
219             }
220             else
221             {
222                 property.PropertyChanged?.Invoke(this, null, value);
223
224                 OnPropertyChanged(property.PropertyName);
225             }
226         }
227
228         internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
229         {
230             if (property == null)
231                 throw new ArgumentNullException(nameof(property));
232
233             if (true == isCreateByXaml)
234             {
235                 if (property.IsReadOnly)
236                     throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
237
238                 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
239                     SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
240             }
241             else
242             {
243                 property.PropertyChanged?.Invoke(this, null, value);
244             }
245         }
246
247         /// <summary>
248         /// Sets the value of the propertyKey.
249         /// </summary>
250         /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
251         /// <param name="value">The value to set.</param>
252         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
253         [EditorBrowsable(EditorBrowsableState.Never)]
254         public void SetValue(BindablePropertyKey propertyKey, object value)
255         {
256             if (propertyKey == null)
257                 throw new ArgumentNullException(nameof(propertyKey));
258
259             SetValue(propertyKey.BindableProperty, value, false, false);
260         }
261
262         /// <summary>
263         /// Set the inherited context to a neated element.
264         /// </summary>
265         /// <param name="bindable">The object on which to set the inherited binding context.</param>
266         /// <param name="value">The inherited context to set.</param>
267         [EditorBrowsable(EditorBrowsableState.Never)]
268         public static void SetInheritedBindingContext(BindableObject bindable, object value)
269         {
270             BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
271             if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
272                 return;
273
274             object oldContext = bindable._inheritedContext;
275
276             if (ReferenceEquals(oldContext, value))
277                 return;
278
279             if (bpContext != null && oldContext == null)
280                 oldContext = bpContext.Value;
281
282             if (bpContext != null && bpContext.Binding != null)
283             {
284                 bpContext.Binding.Context = value;
285                 bindable._inheritedContext = null;
286             }
287             else
288             {
289                 bindable._inheritedContext = value;
290             }
291
292             bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
293             bindable.OnBindingContextChanged();
294         }
295
296         /// <summary>
297         /// Apply the bindings to BindingContext.
298         /// </summary>
299         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
300         [EditorBrowsable(EditorBrowsableState.Never)]
301         protected void ApplyBindings()
302         {
303             ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
304         }
305
306         /// <summary>
307         /// Override this method to execute an action when the BindingContext changes.
308         /// </summary>
309         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
310         [EditorBrowsable(EditorBrowsableState.Never)]
311         protected virtual void OnBindingContextChanged()
312         {
313             BindingContextChanged?.Invoke(this, EventArgs.Empty);
314         }
315
316         /// <summary>
317         /// Call this method from a child class to notify that a change happened on a property.
318         /// </summary>
319         /// <param name="propertyName">The name of the property that changed.</param>
320         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
321         [EditorBrowsable(EditorBrowsableState.Never)]
322         protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
323             => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
324
325         /// <summary>
326         /// Call this method from a child class to notify that a change is going to happen on a property.
327         /// </summary>
328         /// <param name="propertyName">The name of the property that is changing.</param>
329         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
330         [EditorBrowsable(EditorBrowsableState.Never)]
331         protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
332             => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
333
334         /// <summary>
335         /// Unapplies all previously set bindings.
336         /// </summary>
337         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
338         [EditorBrowsable(EditorBrowsableState.Never)]
339         protected void UnapplyBindings()
340         {
341             for (int i = 0, _propertiesCount = _properties.Count; i < _propertiesCount; i++)
342             {
343                 BindablePropertyContext context = _properties[i];
344                 if (context.Binding == null)
345                     continue;
346
347                 context.Binding.Unapply();
348             }
349         }
350
351         internal bool GetIsBound(BindableProperty targetProperty)
352         {
353             if (targetProperty == null)
354                 throw new ArgumentNullException(nameof(targetProperty));
355
356             BindablePropertyContext bpcontext = GetContext(targetProperty);
357             return bpcontext != null && bpcontext.Binding != null;
358         }
359
360         /// <summary>
361         /// Returns the value that is contained the BindableProperty.
362         /// </summary>
363         /// <param name="property0">The BindableProperty instance.</param>
364         /// <param name="property1">The BindableProperty instance.</param>
365         /// <returns>The value that is contained the BindableProperty</returns>
366         internal object[] GetValues(BindableProperty property0, BindableProperty property1)
367         {
368             var values = new object[2];
369
370             for (var i = 0; i < _properties.Count; i++)
371             {
372                 BindablePropertyContext context = _properties[i];
373
374                 if (ReferenceEquals(context.Property, property0))
375                 {
376                     values[0] = context.Value;
377                     property0 = null;
378                 }
379                 else if (ReferenceEquals(context.Property, property1))
380                 {
381                     values[1] = context.Value;
382                     property1 = null;
383                 }
384
385                 if (property0 == null && property1 == null)
386                     return values;
387             }
388
389             if (!ReferenceEquals(property0, null))
390                 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
391             if (!ReferenceEquals(property1, null))
392                 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
393
394             return values;
395         }
396
397         /// <summary>
398         /// Returns the value that is contained the BindableProperty.
399         /// </summary>
400         /// <param name="property0">The BindableProperty instance.</param>
401         /// <param name="property1">The BindableProperty instance.</param>
402         /// <param name="property2">The BindableProperty instance.</param>
403         /// <returns>The value that is contained the BindableProperty</returns>
404         internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
405         {
406             var values = new object[3];
407
408             for (var i = 0; i < _properties.Count; i++)
409             {
410                 BindablePropertyContext context = _properties[i];
411
412                 if (ReferenceEquals(context.Property, property0))
413                 {
414                     values[0] = context.Value;
415                     property0 = null;
416                 }
417                 else if (ReferenceEquals(context.Property, property1))
418                 {
419                     values[1] = context.Value;
420                     property1 = null;
421                 }
422                 else if (ReferenceEquals(context.Property, property2))
423                 {
424                     values[2] = context.Value;
425                     property2 = null;
426                 }
427
428                 if (property0 == null && property1 == null && property2 == null)
429                     return values;
430             }
431
432             if (!ReferenceEquals(property0, null))
433                 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
434             if (!ReferenceEquals(property1, null))
435                 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
436             if (!ReferenceEquals(property2, null))
437                 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
438
439             return values;
440         }
441
442         /// <summary>
443         /// Returns the value that is contained the BindableProperty.
444         /// </summary>
445         /// <param name="properties">The array of the BindableProperty instances</param>
446         /// <returns>The values that is contained the BindableProperty instances.</returns>
447         internal object[] GetValues(params BindableProperty[] properties)
448         {
449             var values = new object[properties.Length];
450             for (var i = 0; i < _properties.Count; i++)
451             {
452                 var context = _properties[i];
453                 var index = properties.IndexOf(context.Property);
454                 if (index < 0)
455                     continue;
456                 values[index] = context.Value;
457             }
458             for (var i = 0; i < values.Length; i++)
459             {
460                 if (!ReferenceEquals(values[i], null))
461                     continue;
462                 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
463             }
464             return values;
465         }
466
467         internal virtual void OnRemoveDynamicResource(BindableProperty property)
468         {
469         }
470
471         internal virtual void OnSetDynamicResource(BindableProperty property, string key)
472         {
473         }
474
475         internal void RemoveDynamicResource(BindableProperty property)
476         {
477             if (property == null)
478                 throw new ArgumentNullException(nameof(property));
479
480             OnRemoveDynamicResource(property);
481             BindablePropertyContext context = GetOrCreateContext(property);
482             context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
483         }
484
485         internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
486         {
487             if (targetProperty == null)
488                 throw new ArgumentNullException(nameof(targetProperty));
489             if (binding == null)
490                 throw new ArgumentNullException(nameof(binding));
491
492             if (fromStyle && !CanBeSetFromStyle(targetProperty))
493                 return;
494
495             var context = GetOrCreateContext(targetProperty);
496             if (fromStyle)
497                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
498             else
499                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
500
501             if (context.Binding != null)
502                 context.Binding.Unapply();
503
504             BindingBase oldBinding = context.Binding;
505             context.Binding = binding;
506
507             targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
508
509             binding.Apply(BindingContext, this, targetProperty);
510         }
511
512         bool CanBeSetFromStyle(BindableProperty property)
513         {
514             var context = GetContext(property);
515             if (context == null)
516                 return true;
517             if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
518                 return true;
519             if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
520                 return true;
521             if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
522                 return true;
523             return false;
524         }
525
526         internal void SetDynamicResource(BindableProperty property, string key)
527         {
528             SetDynamicResource(property, key, false);
529         }
530
531         internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
532         {
533             if (property == null)
534                 throw new ArgumentNullException(nameof(property));
535             if (string.IsNullOrEmpty(key))
536                 throw new ArgumentNullException(nameof(key));
537             if (fromStyle && !CanBeSetFromStyle(property))
538                 return;
539
540             var context = GetOrCreateContext(property);
541
542             context.Attributes |= BindableContextAttributes.IsDynamicResource;
543             if (fromStyle)
544                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
545             else
546                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
547
548             OnSetDynamicResource(property, key);
549         }
550
551         internal void SetValue(BindableProperty property, object value, bool fromStyle)
552         {
553             SetValue(property, value, fromStyle, true);
554         }
555
556         internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
557         {
558             SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
559         }
560
561         /// <summary>
562         /// For internal use.
563         /// </summary>
564         /// <param name="property">The BindableProperty on which to assign a value.</param>
565         /// <param name="value">The value to set</param>
566         /// <param name="attributes">The set value flag</param>
567         [EditorBrowsable(EditorBrowsableState.Never)]
568         internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
569         {
570             SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
571         }
572
573         internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
574         {
575             bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
576             bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
577             bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
578             bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
579             bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
580
581             if (property == null)
582                 throw new ArgumentNullException(nameof(property));
583             if (checkAccess && property.IsReadOnly)
584             {
585                 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
586                 return;
587             }
588
589             if (!converted && !property.TryConvert(ref value))
590             {
591                 Console.WriteLine("SetValue", "Can not convert {0} to type '{1}'", value, property.ReturnType);
592                 return;
593             }
594
595             if (property.ValidateValue != null && !property.ValidateValue(this, value))
596                 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
597
598             if (property.CoerceValue != null)
599                 value = property.CoerceValue(this, value);
600
601             BindablePropertyContext context = GetOrCreateContext(property);
602             if (manuallySet)
603             {
604                 context.Attributes |= BindableContextAttributes.IsManuallySet;
605                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
606             }
607             else
608                 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
609
610             if (fromStyle)
611                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
612             // else omitted on purpose
613
614             bool currentlyApplying = _applying;
615
616             if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
617             {
618                 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
619                 if (delayQueue == null)
620                     context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
621
622                 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
623             }
624             else
625             {
626                 context.Attributes |= BindableContextAttributes.IsBeingSet;
627                 SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
628
629                 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
630                 if (delayQueue != null)
631                 {
632                     while (delayQueue.Count > 0)
633                     {
634                         SetValueArgs s = delayQueue.Dequeue();
635                         SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
636                     }
637
638                     context.DelayedSetters = null;
639                 }
640
641                 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
642             }
643         }
644
645         internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
646         {
647             var prop = _properties.ToArray();
648             for (int i = 0, propLength = prop.Length; i < propLength; i++)
649             {
650                 BindablePropertyContext context = prop[i];
651                 BindingBase binding = context.Binding;
652                 if (binding == null)
653                     continue;
654
655                 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
656                     continue;
657
658                 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
659                 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
660             }
661         }
662
663         static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
664         {
665             object context = bindable._inheritedContext;
666             var oldBinding = oldBindingBase as Binding;
667             var newBinding = newBindingBase as Binding;
668
669             if (context == null && oldBinding != null)
670                 context = oldBinding.Context;
671             if (context != null && newBinding != null)
672                 newBinding.Context = context;
673         }
674
675         static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
676         {
677             bindable._inheritedContext = null;
678             bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
679             bindable.OnBindingContextChanged();
680         }
681
682         void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
683         {
684             if (property == null)
685                 throw new ArgumentNullException(nameof(property));
686
687             if (checkAccess && property.IsReadOnly)
688                 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
689
690             BindablePropertyContext bpcontext = GetContext(property);
691             if (bpcontext == null)
692                 return;
693
694             if (fromStyle && !CanBeSetFromStyle(property))
695                 return;
696
697             object original = bpcontext.Value;
698
699             object newValue = property.GetDefaultValue(this);
700
701             bool same = Equals(original, newValue);
702             if (!same)
703             {
704                 property.PropertyChanging?.Invoke(this, original, newValue);
705
706                 OnPropertyChanging(property.PropertyName);
707             }
708
709             bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
710             bpcontext.Value = newValue;
711             if (property.DefaultValueCreator == null)
712                 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
713             else
714                 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
715
716             if (!same)
717             {
718                 OnPropertyChanged(property.PropertyName);
719                 property.PropertyChanged?.Invoke(this, original, newValue);
720             }
721         }
722
723         [MethodImpl(MethodImplOptions.AggressiveInlining)]
724         BindablePropertyContext CreateAndAddContext(BindableProperty property)
725         {
726             var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
727
728             if (property.DefaultValueCreator == null)
729                 context.Attributes = BindableContextAttributes.IsDefaultValue;
730             else
731                 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
732
733             _properties.Add(context);
734             return context;
735         }
736
737         [MethodImpl(MethodImplOptions.AggressiveInlining)]
738         BindablePropertyContext GetContext(BindableProperty property)
739         {
740             List<BindablePropertyContext> properties = _properties;
741
742             for (var i = 0; i < properties.Count; i++)
743             {
744                 BindablePropertyContext context = properties[i];
745                 if (ReferenceEquals(context.Property, property))
746                     return context;
747             }
748
749             return null;
750         }
751
752         [MethodImpl(MethodImplOptions.AggressiveInlining)]
753         BindablePropertyContext GetOrCreateContext(BindableProperty property)
754         {
755             BindablePropertyContext context = GetContext(property);
756             if (context == null)
757             {
758                 context = CreateAndAddContext(property);
759             }
760             else if (property.DefaultValueCreator != null)
761             {
762                 context.Value = property.DefaultValueCreator(this); //Update Value from dali
763             }//added by xb.teng
764
765             return context;
766         }
767
768         void RemoveBinding(BindableProperty property, BindablePropertyContext context)
769         {
770             context.Binding.Unapply();
771
772             property.BindingChanging?.Invoke(this, context.Binding, null);
773
774             context.Binding = null;
775         }
776
777         void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
778         {
779             if (property == null)
780                 throw new ArgumentNullException(nameof(property));
781
782             if (checkAccess && property.IsReadOnly)
783                 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
784
785             if (fromStyle && !CanBeSetFromStyle(property))
786                 return;
787
788             SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
789                 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
790                 false);
791         }
792
793         void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
794         {
795             object original = context.Value;
796             bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
797             bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
798             bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
799             bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
800
801             bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
802             if (!silent && (!same || raiseOnEqual))
803             {
804                 property.PropertyChanging?.Invoke(this, original, value);
805
806                 OnPropertyChanging(property.PropertyName);
807             }
808
809             if (!same || raiseOnEqual)
810             {
811                 context.Value = value;
812             }
813
814             context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
815             context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
816
817             if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
818                 RemoveDynamicResource(property);
819
820             BindingBase binding = context.Binding;
821             if (binding != null)
822             {
823                 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
824                 {
825                     RemoveBinding(property, context);
826                     binding = null;
827                 }
828             }
829
830             if (!silent)
831             {
832                 if ((!same || raiseOnEqual))
833                 {
834                     property.PropertyChanged?.Invoke(this, original, value);
835
836                     if (binding != null && !currentlyApplying)
837                     {
838                         _applying = true;
839                         binding.Apply(true);
840                         _applying = false;
841                     }
842
843                     OnPropertyChanged(property.PropertyName);
844                 }
845                 else if (true == same && true == forceSendChangeSignal)
846                 {
847                     if (binding != null && !currentlyApplying)
848                     {
849                         _applying = true;
850                         binding.Apply(true);
851                         _applying = false;
852                     }
853
854                     OnPropertyChanged(property.PropertyName);
855                 }
856             }
857         }
858
859         [Flags]
860         enum BindableContextAttributes
861         {
862             IsManuallySet = 1 << 0,
863             IsBeingSet = 1 << 1,
864             IsDynamicResource = 1 << 2,
865             IsSetFromStyle = 1 << 3,
866             IsDefaultValue = 1 << 4,
867             IsDefaultValueCreated = 1 << 5,
868         }
869
870         class BindablePropertyContext
871         {
872             public BindableContextAttributes Attributes;
873             public BindingBase Binding;
874             public Queue<SetValueArgs> DelayedSetters;
875             public BindableProperty Property;
876             public object Value;
877         }
878
879         [Flags]
880         internal enum SetValuePrivateFlags
881         {
882             None = 0,
883             CheckAccess = 1 << 0,
884             Silent = 1 << 1,
885             ManuallySet = 1 << 2,
886             FromStyle = 1 << 3,
887             Converted = 1 << 4,
888             Default = CheckAccess
889         }
890
891         class SetValueArgs
892         {
893             public readonly SetValueFlags Attributes;
894             public readonly BindablePropertyContext Context;
895             public readonly bool CurrentlyApplying;
896             public readonly BindableProperty Property;
897             public readonly object Value;
898
899             public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
900             {
901                 Property = property;
902                 Context = context;
903                 Value = value;
904                 CurrentlyApplying = currentlyApplying;
905                 Attributes = attributes;
906             }
907         }
908     }
909 }
910
911 namespace Tizen.NUI.Binding.Internals
912 {
913     /// <summary>
914     /// SetValueFlags. For internal use.
915     /// </summary>
916     [Flags]
917     [EditorBrowsable(EditorBrowsableState.Never)]
918     public enum SetValueFlags
919     {
920         /// <summary>
921         /// None.
922         /// </summary>
923         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
924         [EditorBrowsable(EditorBrowsableState.Never)]
925         None = 0,
926
927         /// <summary>
928         /// Clear OneWay bindings.
929         /// </summary>
930         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
931         [EditorBrowsable(EditorBrowsableState.Never)]
932         ClearOneWayBindings = 1 << 0,
933
934         /// <summary>
935         /// Clear TwoWay bindings.
936         /// </summary>
937         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
938         [EditorBrowsable(EditorBrowsableState.Never)]
939         ClearTwoWayBindings = 1 << 1,
940
941         /// <summary>
942         /// Clear dynamic resource.
943         /// </summary>
944         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
945         [EditorBrowsable(EditorBrowsableState.Never)]
946         ClearDynamicResource = 1 << 2,
947
948         /// <summary>
949         /// Raise or equal.
950         /// </summary>
951         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
952         [EditorBrowsable(EditorBrowsableState.Never)]
953         RaiseOnEqual = 1 << 3
954     }
955 }