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