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