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