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