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