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