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