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