[NUI] Add ThemeManager (#2034)
[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                 BindablePropertyContext context = _properties [i];
343                 if (context.Binding == null)
344                     continue;
345
346                 context.Binding.Unapply();
347             }
348         }
349
350         internal bool GetIsBound(BindableProperty targetProperty)
351         {
352             if (targetProperty == null)
353                 throw new ArgumentNullException(nameof(targetProperty));
354
355             BindablePropertyContext bpcontext = GetContext(targetProperty);
356             return bpcontext != null && bpcontext.Binding != null;
357         }
358
359         /// <summary>
360         /// Returns the value that is contained the BindableProperty.
361         /// </summary>
362         /// <param name="property0">The BindableProperty instance.</param>
363         /// <param name="property1">The BindableProperty instance.</param>
364         /// <returns>The value that is contained the BindableProperty</returns>
365         internal object[] GetValues(BindableProperty property0, BindableProperty property1)
366         {
367             var values = new object[2];
368
369             for (var i = 0; i < _properties.Count; i++)
370             {
371                 BindablePropertyContext context = _properties[i];
372
373                 if (ReferenceEquals(context.Property, property0))
374                 {
375                     values[0] = context.Value;
376                     property0 = null;
377                 }
378                 else if (ReferenceEquals(context.Property, property1))
379                 {
380                     values[1] = context.Value;
381                     property1 = null;
382                 }
383
384                 if (property0 == null && property1 == null)
385                     return values;
386             }
387
388             if (!ReferenceEquals(property0, null))
389                 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
390             if (!ReferenceEquals(property1, null))
391                 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
392
393             return values;
394         }
395
396         /// <summary>
397         /// Returns the value that is contained the BindableProperty.
398         /// </summary>
399         /// <param name="property0">The BindableProperty instance.</param>
400         /// <param name="property1">The BindableProperty instance.</param>
401         /// <param name="property2">The BindableProperty instance.</param>
402         /// <returns>The value that is contained the BindableProperty</returns>
403         internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
404         {
405             var values = new object[3];
406
407             for (var i = 0; i < _properties.Count; i++)
408             {
409                 BindablePropertyContext context = _properties[i];
410
411                 if (ReferenceEquals(context.Property, property0))
412                 {
413                     values[0] = context.Value;
414                     property0 = null;
415                 }
416                 else if (ReferenceEquals(context.Property, property1))
417                 {
418                     values[1] = context.Value;
419                     property1 = null;
420                 }
421                 else if (ReferenceEquals(context.Property, property2))
422                 {
423                     values[2] = context.Value;
424                     property2 = null;
425                 }
426
427                 if (property0 == null && property1 == null && property2 == null)
428                     return values;
429             }
430
431             if (!ReferenceEquals(property0, null))
432                 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
433             if (!ReferenceEquals(property1, null))
434                 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
435             if (!ReferenceEquals(property2, null))
436                 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
437
438             return values;
439         }
440
441         /// <summary>
442         /// Returns the value that is contained the BindableProperty.
443         /// </summary>
444         /// <param name="properties">The array of the BindableProperty instances</param>
445         /// <returns>The values that is contained the BindableProperty instances.</returns>
446         internal object[] GetValues(params BindableProperty[] properties)
447         {
448             var values = new object[properties.Length];
449             for (var i = 0; i < _properties.Count; i++) {
450                 var context = _properties[i];
451                 var index = properties.IndexOf(context.Property);
452                 if (index < 0)
453                     continue;
454                 values[index] = context.Value;
455             }
456             for (var i = 0; i < values.Length; i++) {
457                 if (!ReferenceEquals(values[i], null))
458                     continue;
459                 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
460             }
461             return values;
462         }
463
464         internal virtual void OnRemoveDynamicResource(BindableProperty property)
465         {
466         }
467
468         internal virtual void OnSetDynamicResource(BindableProperty property, string key)
469         {
470         }
471
472         internal void RemoveDynamicResource(BindableProperty property)
473         {
474             if (property == null)
475                 throw new ArgumentNullException(nameof(property));
476
477             OnRemoveDynamicResource(property);
478             BindablePropertyContext context = GetOrCreateContext(property);
479             context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
480         }
481
482         internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
483         {
484             if (targetProperty == null)
485                 throw new ArgumentNullException(nameof(targetProperty));
486             if (binding == null)
487                 throw new ArgumentNullException(nameof(binding));
488
489             if (fromStyle && !CanBeSetFromStyle(targetProperty))
490                 return;
491
492             var context = GetOrCreateContext(targetProperty);
493             if (fromStyle)
494                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
495             else
496                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
497
498             if (context.Binding != null)
499                 context.Binding.Unapply();
500
501             BindingBase oldBinding = context.Binding;
502             context.Binding = binding;
503
504             targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
505
506             binding.Apply(BindingContext, this, targetProperty);
507         }
508
509         bool CanBeSetFromStyle(BindableProperty property)
510         {
511             var context = GetContext(property);
512             if (context == null)
513                 return true;
514             if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
515                 return true;
516             if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
517                 return true;
518             if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
519                 return true;
520             return false;
521         }
522
523         internal void SetDynamicResource(BindableProperty property, string key)
524         {
525             SetDynamicResource(property, key, false);
526         }
527
528         internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
529         {
530             if (property == null)
531                 throw new ArgumentNullException(nameof(property));
532             if (string.IsNullOrEmpty(key))
533                 throw new ArgumentNullException(nameof(key));
534             if (fromStyle && !CanBeSetFromStyle(property))
535                 return;
536
537             var context = GetOrCreateContext(property);
538
539             context.Attributes |= BindableContextAttributes.IsDynamicResource;
540             if (fromStyle)
541                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
542             else
543                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
544
545             OnSetDynamicResource(property, key);
546         }
547
548         internal void SetValue(BindableProperty property, object value, bool fromStyle)
549         {
550             SetValue(property, value, fromStyle, true);
551         }
552
553         internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
554         {
555             SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
556         }
557
558         /// <summary>
559         /// For internal use.
560         /// </summary>
561         /// <param name="property">The BindableProperty on which to assign a value.</param>
562         /// <param name="value">The value to set</param>
563         /// <param name="attributes">The set value flag</param>
564         [EditorBrowsable(EditorBrowsableState.Never)]
565         internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
566         {
567             SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
568         }
569
570         internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
571         {
572             bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
573             bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
574             bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
575             bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
576             bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
577
578             if (property == null)
579                 throw new ArgumentNullException(nameof(property));
580             if (checkAccess && property.IsReadOnly)
581             {
582                 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
583                 return;
584             }
585
586             if (!converted && !property.TryConvert(ref value))
587             {
588                 Console.WriteLine("SetValue", "Can not convert {0} to type '{1}'", value, property.ReturnType);
589                 return;
590             }
591
592             if (property.ValidateValue != null && !property.ValidateValue(this, value))
593                 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
594
595             if (property.CoerceValue != null)
596                 value = property.CoerceValue(this, value);
597
598             BindablePropertyContext context = GetOrCreateContext(property);
599             if (manuallySet) {
600                 context.Attributes |= BindableContextAttributes.IsManuallySet;
601                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
602             } else
603                 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
604
605             if (fromStyle)
606                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
607             // else omitted on purpose
608
609             bool currentlyApplying = _applying;
610
611             if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
612             {
613                 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
614                 if (delayQueue == null)
615                     context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
616
617                 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
618             }
619             else
620             {
621                 context.Attributes |= BindableContextAttributes.IsBeingSet;
622                 SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
623
624                 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
625                 if (delayQueue != null)
626                 {
627                     while (delayQueue.Count > 0)
628                     {
629                         SetValueArgs s = delayQueue.Dequeue();
630                         SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
631                     }
632
633                     context.DelayedSetters = null;
634                 }
635
636                 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
637             }
638         }
639
640         internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
641         {
642             var prop = _properties.ToArray();
643             for (int i = 0, propLength = prop.Length; i < propLength; i++) {
644                 BindablePropertyContext context = prop [i];
645                 BindingBase binding = context.Binding;
646                 if (binding == null)
647                     continue;
648
649                 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
650                     continue;
651
652                 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
653                 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
654             }
655         }
656
657         static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
658         {
659             object context = bindable._inheritedContext;
660             var oldBinding = oldBindingBase as Binding;
661             var newBinding = newBindingBase as Binding;
662
663             if (context == null && oldBinding != null)
664                 context = oldBinding.Context;
665             if (context != null && newBinding != null)
666                 newBinding.Context = context;
667         }
668
669         static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
670         {
671             bindable._inheritedContext = null;
672             bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged:true);
673             bindable.OnBindingContextChanged();
674         }
675
676         void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
677         {
678             if (property == null)
679                 throw new ArgumentNullException(nameof(property));
680
681             if (checkAccess && property.IsReadOnly)
682                 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
683
684             BindablePropertyContext bpcontext = GetContext(property);
685             if (bpcontext == null)
686                 return;
687
688             if (fromStyle && !CanBeSetFromStyle(property))
689                 return;
690
691             object original = bpcontext.Value;
692
693             object newValue = property.GetDefaultValue(this);
694
695             bool same = Equals(original, newValue);
696             if (!same)
697             {
698                 property.PropertyChanging?.Invoke(this, original, newValue);
699
700                 OnPropertyChanging(property.PropertyName);
701             }
702
703             bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
704             bpcontext.Value = newValue;
705             if (property.DefaultValueCreator == null)
706                 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
707             else
708                 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
709
710             if (!same)
711             {
712                 OnPropertyChanged(property.PropertyName);
713                 property.PropertyChanged?.Invoke(this, original, newValue);
714             }
715         }
716
717         [MethodImpl(MethodImplOptions.AggressiveInlining)]
718         BindablePropertyContext CreateAndAddContext(BindableProperty property)
719         {
720             var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
721
722             if (property.DefaultValueCreator == null)
723                 context.Attributes = BindableContextAttributes.IsDefaultValue;
724             else
725                 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
726
727             _properties.Add(context);
728             return context;
729         }
730
731         [MethodImpl(MethodImplOptions.AggressiveInlining)]
732         BindablePropertyContext GetContext(BindableProperty property)
733         {
734             List<BindablePropertyContext> properties = _properties;
735
736             for (var i = 0; i < properties.Count; i++)
737             {
738                 BindablePropertyContext context = properties[i];
739                 if (ReferenceEquals(context.Property, property))
740                     return context;
741             }
742
743             return null;
744         }
745
746         [MethodImpl(MethodImplOptions.AggressiveInlining)]
747         BindablePropertyContext GetOrCreateContext(BindableProperty property)
748         {
749             BindablePropertyContext context = GetContext(property);
750             if (context == null)
751             {
752                 context = CreateAndAddContext(property);
753             }
754             else if (property.DefaultValueCreator != null )
755             {
756                 context.Value = property.DefaultValueCreator(this); //Update Value from dali
757             }//added by xb.teng
758
759             return context;
760         }
761
762         void RemoveBinding(BindableProperty property, BindablePropertyContext context)
763         {
764             context.Binding.Unapply();
765
766             property.BindingChanging?.Invoke(this, context.Binding, null);
767
768             context.Binding = null;
769         }
770
771         void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
772         {
773             if (property == null)
774                 throw new ArgumentNullException(nameof(property));
775
776             if (checkAccess && property.IsReadOnly)
777                 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
778
779             if (fromStyle && !CanBeSetFromStyle(property))
780                 return;
781
782             SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
783                 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
784                 false);
785         }
786
787         void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
788         {
789             object original = context.Value;
790             bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
791             bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
792             bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
793             bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
794
795             bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
796             if (!silent && (!same || raiseOnEqual))
797             {
798                 property.PropertyChanging?.Invoke(this, original, value);
799
800                 OnPropertyChanging(property.PropertyName);
801             }
802
803             if (!same || raiseOnEqual)
804             {
805                 context.Value = value;
806             }
807
808             context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
809             context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
810
811             if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
812                 RemoveDynamicResource(property);
813
814             BindingBase binding = context.Binding;
815             if (binding != null)
816             {
817                 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
818                 {
819                     RemoveBinding(property, context);
820                     binding = null;
821                 }
822             }
823
824             if (!silent)
825             {
826                 if ((!same || raiseOnEqual))
827                 {
828                     property.PropertyChanged?.Invoke(this, original, value);
829
830                     if (binding != null && !currentlyApplying)
831                     {
832                         _applying = true;
833                         binding.Apply(true);
834                         _applying = false;
835                     }
836
837                     OnPropertyChanged(property.PropertyName);
838                 }
839                 else if (true == same && true == forceSendChangeSignal)
840                 {
841                     if (binding != null && !currentlyApplying)
842                     {
843                         _applying = true;
844                         binding.Apply(true);
845                         _applying = false;
846                     }
847
848                     OnPropertyChanged(property.PropertyName);
849                 }
850             }
851         }
852
853         [Flags]
854         enum BindableContextAttributes
855         {
856             IsManuallySet = 1 << 0,
857             IsBeingSet = 1 << 1,
858             IsDynamicResource = 1 << 2,
859             IsSetFromStyle = 1 << 3,
860             IsDefaultValue = 1 << 4,
861             IsDefaultValueCreated = 1 << 5,
862         }
863
864         class BindablePropertyContext
865         {
866             public BindableContextAttributes Attributes;
867             public BindingBase Binding;
868             public Queue<SetValueArgs> DelayedSetters;
869             public BindableProperty Property;
870             public object Value;
871         }
872
873         [Flags]
874         internal enum SetValuePrivateFlags
875         {
876             None = 0,
877             CheckAccess = 1 << 0,
878             Silent = 1 << 1,
879             ManuallySet = 1 << 2,
880             FromStyle = 1 << 3,
881             Converted = 1 << 4,
882             Default = CheckAccess
883         }
884
885         class SetValueArgs
886         {
887             public readonly SetValueFlags Attributes;
888             public readonly BindablePropertyContext Context;
889             public readonly bool CurrentlyApplying;
890             public readonly BindableProperty Property;
891             public readonly object Value;
892
893             public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
894             {
895                 Property = property;
896                 Context = context;
897                 Value = value;
898                 CurrentlyApplying = currentlyApplying;
899                 Attributes = attributes;
900             }
901         }
902     }
903 }
904
905 namespace Tizen.NUI.Binding.Internals
906 {
907     /// <summary>
908     /// SetValueFlags. For internal use.
909     /// </summary>
910     [Flags]
911     [EditorBrowsable(EditorBrowsableState.Never)]
912     public enum SetValueFlags
913     {
914         /// <summary>
915         /// None.
916         /// </summary>
917         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
918         [EditorBrowsable(EditorBrowsableState.Never)]
919         None = 0,
920
921         /// <summary>
922         /// Clear OneWay bindings.
923         /// </summary>
924         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
925         [EditorBrowsable(EditorBrowsableState.Never)]
926         ClearOneWayBindings = 1 << 0,
927
928         /// <summary>
929         /// Clear TwoWay bindings.
930         /// </summary>
931         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
932         [EditorBrowsable(EditorBrowsableState.Never)]
933         ClearTwoWayBindings = 1 << 1,
934
935         /// <summary>
936         /// Clear dynamic resource.
937         /// </summary>
938         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
939         [EditorBrowsable(EditorBrowsableState.Never)]
940         ClearDynamicResource = 1 << 2,
941
942         /// <summary>
943         /// Raise or equal.
944         /// </summary>
945         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
946         [EditorBrowsable(EditorBrowsableState.Never)]
947         RaiseOnEqual = 1 << 3
948     }
949 }