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