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