2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using System.Diagnostics;
22 using System.Reflection;
24 using System.Runtime.CompilerServices;
25 using Tizen.NUI.Binding.Internals;
27 namespace Tizen.NUI.Binding
30 /// Provides a mechanism by which application developers can propagate changes that are made to data in one object to another.
32 /// <since_tizen> 9 </since_tizen>
33 public abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
36 /// Implements the bound property whose interface is provided by the BindingContext property.
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);
43 readonly Dictionary<BindableProperty, BindablePropertyContext> properties = new Dictionary<BindableProperty, BindablePropertyContext>(4);
46 object inheritedContext;
49 /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
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
55 get { return inheritedContext ?? GetValue(BindingContextProperty); }
56 set { SetValue(BindingContextProperty, value); }
59 [EditorBrowsable(EditorBrowsableState.Never)]
60 public int LineNumber { get; set; } = -1;
62 [EditorBrowsable(EditorBrowsableState.Never)]
63 public int LinePosition { get; set; } = -1;
65 void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
67 SetDynamicResource(property, key, false);
71 /// Raised when a property has changed.
73 /// <since_tizen> 9 </since_tizen>
74 public event PropertyChangedEventHandler PropertyChanged;
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)
81 if (null == other) return;
83 Type type1 = this.GetType();
84 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
86 Type type2 = other.GetType();
87 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
89 if (null != nameToBindableProperty1)
91 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
93 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
95 if (null != bindableProperty && other.IsSet(bindableProperty))
97 object value = other.GetValue(bindableProperty);
98 InternalSetValue(keyValuePair.Value, value);
105 /// Copy all binding from other object.
107 /// <param name="other"></param>
108 [EditorBrowsable(EditorBrowsableState.Never)]
109 public void CopyBindingRelationShip(BindableObject other)
116 foreach (var property in properties)
118 RemoveBinding(property.Key);
121 foreach (var property in other.properties)
123 if (null != property.Value.Binding)
125 var binding = property.Value.Binding;
126 other.RemoveBinding(property.Key);
127 SetBinding(property.Key, binding);
133 /// Raised whenever the BindingContext property changes.
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;
139 internal void ClearValue(BindableProperty property, bool fromStyle)
141 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
145 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
147 /// <param name="property">The BindableProperty to clear</param>
148 internal void ClearValue(BindableProperty property)
150 ClearValue(property, fromStyle: false, checkAccess: true);
154 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
156 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
157 internal void ClearValue(BindablePropertyKey propertyKey)
159 if (propertyKey == null)
160 throw new ArgumentNullException(nameof(propertyKey));
162 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
166 /// Return true if the target property exists and has been set.
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)
172 if (targetProperty == null)
173 throw new ArgumentNullException(nameof(targetProperty));
175 var bpcontext = GetContext(targetProperty);
176 return bpcontext != null
177 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
181 /// Returns the value that is contained the BindableProperty.
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)
189 if (property == null)
190 throw new ArgumentNullException(nameof(property));
192 if (!IsBound && property.ValueGetter != null)
194 return property.ValueGetter(this);
197 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
200 return property.DefaultValue;
202 return context.Value;
206 /// Raised when a property is about to change.
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;
213 /// Removes a previously set binding.
215 /// <param name="property">The BindableProperty from which to remove bindings.</param>
216 internal void RemoveBinding(BindableProperty property)
218 if (property == null)
219 throw new ArgumentNullException(nameof(property));
221 BindablePropertyContext context = GetContext(property);
222 if (context == null || context.Binding == null)
225 RemoveBinding(property, context);
229 /// Assigns a binding to a property.
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)
237 SetBinding(targetProperty, binding, false);
240 /// Internal used, will never changed to not hidden.
241 [EditorBrowsable(EditorBrowsableState.Never)]
242 public virtual bool IsCreateByXaml
248 /// This will be public opened in next ACR.
249 [EditorBrowsable(EditorBrowsableState.Never)]
250 public void EnforceNotifyBindedInstance(BindableProperty property)
252 if (null != property)
254 BindablePropertyContext context = GetOrCreateContext(property);
255 BindingBase binding = context.Binding;
257 var currentlyApplying = applying;
259 if (binding != null && !currentlyApplying)
266 OnPropertyChanged(property.PropertyName);
268 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
270 if (null != propertyGroup)
272 foreach (var relativeProperty in propertyGroup)
274 if (relativeProperty != property)
276 var relativeContext = GetOrCreateContext(relativeProperty);
277 var relativeBinding = relativeContext.Binding;
279 if (null != relativeBinding)
282 relativeBinding.Apply(true);
286 OnPropertyChanged(relativeProperty.PropertyName);
294 /// Sets the value of the specified property.
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)
303 InternalSetValue(property, value);
304 ChangedPropertiesSetExcludingStyle.Add(property);
307 internal void InternalSetValue(BindableProperty property, object value)
311 SetValue(property, value, false, true);
315 if (null == property)
317 throw new ArgumentNullException(nameof(property));
320 object oldvalue = null;
321 BindablePropertyContext context = GetOrCreateContext(property);
324 context.Attributes |= BindableContextAttributes.IsManuallySet;
325 oldvalue = context.Value;
326 context.Value = value;
329 property.PropertyChanged?.Invoke(this, oldvalue, value);
331 OnPropertyChanged(property.PropertyName);
332 OnPropertyChangedWithData(property);
336 private HashSet<BindableProperty> changedPropertiesSetExcludingStyle;
337 internal protected HashSet<BindableProperty> ChangedPropertiesSetExcludingStyle
341 if (null == changedPropertiesSetExcludingStyle)
343 changedPropertiesSetExcludingStyle = new HashSet<BindableProperty>();
346 return changedPropertiesSetExcludingStyle;
351 /// Sets the value of the propertyKey.
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)
359 if (propertyKey == null)
360 throw new ArgumentNullException(nameof(propertyKey));
362 SetValue(propertyKey.BindableProperty, value, false, false);
366 /// Set the inherited context to a neated element.
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)
374 if (null == bindable)
376 throw new ArgumentNullException(nameof(bindable));
379 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
380 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
383 object oldContext = bindable.inheritedContext;
385 if (ReferenceEquals(oldContext, value))
388 if (bpContext != null && oldContext == null)
389 oldContext = bpContext.Value;
391 if (bpContext != null && bpContext.Binding != null)
393 bpContext.Binding.Context = value;
394 bindable.inheritedContext = null;
398 bindable.inheritedContext = value;
401 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
402 bindable.OnBindingContextChanged();
406 /// Register the properties which can effect each other in Binding to same group.
408 [EditorBrowsable(EditorBrowsableState.Never)]
409 public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
411 if (!PropertyToGroup.ContainsKey(property))
413 PropertyToGroup.Add(property, group);
416 if (null != group && !(group.Contains(property)))
422 /// Apply the bindings to BindingContext.
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()
428 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
432 /// Override this method to execute an action when the BindingContext changes.
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()
438 BindingContextChanged?.Invoke(this, EventArgs.Empty);
442 /// Call this method from a child class to notify that a change happened on a property.
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));
451 /// Call this method from a child class to notify that a change is going to happen on a property.
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));
460 /// Method that is called when a bound property is changed.
462 [EditorBrowsable(EditorBrowsableState.Never)]
463 protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
466 /// Unapplies all previously set bindings.
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()
472 foreach (var context in properties.Values)
474 if (context.Binding == null)
477 context.Binding.Unapply();
481 internal bool GetIsBound(BindableProperty targetProperty)
483 if (targetProperty == null)
484 throw new ArgumentNullException(nameof(targetProperty));
486 BindablePropertyContext bpcontext = GetContext(targetProperty);
487 return bpcontext != null && bpcontext.Binding != null;
491 /// Returns the value that is contained the BindableProperty.
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)
498 var values = new object[2];
500 foreach (var context in properties.Values)
502 if (ReferenceEquals(context.Property, property0))
504 values[0] = context.Value;
507 else if (ReferenceEquals(context.Property, property1))
509 values[1] = context.Value;
513 if (property0 == null && property1 == null)
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;
526 /// Returns the value that is contained the BindableProperty.
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)
534 var values = new object[3];
536 foreach (var context in properties.Values)
538 if (ReferenceEquals(context.Property, property0))
540 values[0] = context.Value;
543 else if (ReferenceEquals(context.Property, property1))
545 values[1] = context.Value;
548 else if (ReferenceEquals(context.Property, property2))
550 values[2] = context.Value;
554 if (property0 == null && property1 == null && property2 == null)
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;
569 /// Returns the value that is contained the BindableProperty.
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)
575 var values = new object[properties.Length];
576 foreach (var context in this.properties.Values)
578 var index = properties.IndexOf(context.Property);
581 values[index] = context.Value;
583 for (var i = 0; i < values.Length; i++)
585 if (!ReferenceEquals(values[i], null))
587 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
592 internal virtual void OnRemoveDynamicResource(BindableProperty property)
596 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
600 internal void RemoveDynamicResource(BindableProperty property)
602 if (property == null)
603 throw new ArgumentNullException(nameof(property));
605 OnRemoveDynamicResource(property);
606 BindablePropertyContext context = GetOrCreateContext(property);
607 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
610 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
612 if (targetProperty == null)
613 throw new ArgumentNullException(nameof(targetProperty));
615 throw new ArgumentNullException(nameof(binding));
617 if (fromStyle && !CanBeSetFromStyle(targetProperty))
622 var context = GetOrCreateContext(targetProperty);
624 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
626 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
628 if (context.Binding != null)
629 context.Binding.Unapply();
631 BindingBase oldBinding = context.Binding;
632 context.Binding = binding;
634 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
636 binding.Apply(BindingContext, this, targetProperty);
639 bool CanBeSetFromStyle(BindableProperty property)
641 var context = GetContext(property);
644 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
646 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
648 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
653 internal void SetDynamicResource(BindableProperty property, string key)
655 SetDynamicResource(property, key, false);
658 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
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))
667 var context = GetOrCreateContext(property);
669 context.Attributes |= BindableContextAttributes.IsDynamicResource;
671 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
673 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
675 OnSetDynamicResource(property, key);
678 internal void SetValue(BindableProperty property, object value, bool fromStyle)
680 SetValue(property, value, fromStyle, true);
683 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
685 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None);
689 /// For internal use.
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)
697 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default);
700 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
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;
708 if (property == null)
709 throw new ArgumentNullException(nameof(property));
710 if (checkAccess && property.IsReadOnly)
712 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
716 if (!converted && !property.TryConvert(ref value))
718 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
722 if (property.ValidateValue != null && !property.ValidateValue(this, value))
723 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
725 if (property.CoerceValue != null)
726 value = property.CoerceValue(this, value);
728 BindablePropertyContext context = GetOrCreateContext(property);
731 context.Attributes |= BindableContextAttributes.IsManuallySet;
732 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
736 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
741 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
743 // else omitted on purpose
745 bool currentlyApplying = applying;
747 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
749 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
750 if (delayQueue == null)
751 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
753 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
757 context.Attributes |= BindableContextAttributes.IsBeingSet;
758 SetValueActual(property, context, value, currentlyApplying, attributes, silent);
760 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
761 if (delayQueue != null)
763 while (delayQueue.Count > 0)
765 SetValueArgs s = delayQueue.Dequeue();
766 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, s.Attributes);
769 context.DelayedSetters = null;
772 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
776 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
778 var prop = properties.Values.ToArray();
779 for (int i = 0, propLength = prop.Length; i < propLength; i++)
781 BindablePropertyContext context = prop[i];
782 BindingBase binding = context.Binding;
786 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
789 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
790 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
795 /// Check if object is bound or not.
796 /// This API used for legacy codes.
797 /// Should be removed after all app usage replaced into IsBound.
799 [Obsolete("This has been deprecated in API11. Use IsBound property instead.")]
800 internal bool IsBinded
813 /// Check if object is bound or not.
815 [EditorBrowsable(EditorBrowsableState.Never)]
822 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
824 bindable.inheritedContext = null;
825 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
826 bindable.OnBindingContextChanged();
828 if (newvalue is BindableObject targetBindableObject)
830 targetBindableObject.IsBound = true;
834 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
836 object context = bindable.inheritedContext;
837 var oldBinding = oldBindingBase as Binding;
838 var newBinding = newBindingBase as Binding;
840 if (context == null && oldBinding != null)
841 context = oldBinding.Context;
842 if (context != null && newBinding != null)
843 newBinding.Context = context;
846 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
848 if (property == null)
849 throw new ArgumentNullException(nameof(property));
851 if (checkAccess && property.IsReadOnly)
852 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
854 BindablePropertyContext bpcontext = GetContext(property);
855 if (bpcontext == null)
858 if (fromStyle && !CanBeSetFromStyle(property))
861 object original = bpcontext.Value;
863 object newValue = property.GetDefaultValue(this);
865 bool same = Equals(original, newValue);
868 property.PropertyChanging?.Invoke(this, original, newValue);
870 OnPropertyChanging(property.PropertyName);
873 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
874 bpcontext.Value = newValue;
875 if (property.DefaultValueCreator == null)
876 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
878 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
882 OnPropertyChanged(property.PropertyName);
883 OnPropertyChangedWithData(property);
884 property.PropertyChanged?.Invoke(this, original, newValue);
888 [MethodImpl(MethodImplOptions.AggressiveInlining)]
889 BindablePropertyContext CreateAndAddContext(BindableProperty property)
891 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
893 if (property.DefaultValueCreator == null)
894 context.Attributes = BindableContextAttributes.IsDefaultValue;
896 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
898 properties.Add(property, context);
902 [MethodImpl(MethodImplOptions.AggressiveInlining)]
903 BindablePropertyContext GetContext(BindableProperty property) => properties.TryGetValue(property, out var result) ? result : null;
905 [MethodImpl(MethodImplOptions.AggressiveInlining)]
906 BindablePropertyContext GetOrCreateContext(BindableProperty property)
908 BindablePropertyContext context = GetContext(property);
911 context = CreateAndAddContext(property);
913 else if (property.ValueGetter != null)
915 context.Value = property.ValueGetter(this); //Update Value from dali
916 }//added by xiaohui.fang
917 else if (property.DefaultValueCreator != null) //This will be removed in the future.
919 context.Value = property.DefaultValueCreator(this); //Update Value from dali
925 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
927 context.Binding.Unapply();
929 property.BindingChanging?.Invoke(this, context.Binding, null);
931 context.Binding = null;
934 internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
936 if (property == null)
937 throw new ArgumentNullException(nameof(property));
939 if (checkAccess && property.IsReadOnly)
940 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
942 if (fromStyle && !CanBeSetFromStyle(property))
945 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
946 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0));
949 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, bool silent = false)
951 object original = context.Value;
952 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
953 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
954 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
955 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
957 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
958 if (!silent && (!same || raiseOnEqual))
960 property.PropertyChanging?.Invoke(this, original, value);
962 OnPropertyChanging(property.PropertyName);
965 if (!same || raiseOnEqual)
967 context.Value = value;
970 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
971 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
973 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
974 RemoveDynamicResource(property);
976 BindingBase binding = context.Binding;
979 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
981 RemoveBinding(property, context);
986 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
988 if (!silent && (!same || raiseOnEqual))
990 property.PropertyChanged?.Invoke(this, original, value);
992 if (binding != null && !currentlyApplying)
999 OnPropertyChanged(property.PropertyName);
1001 if (null != propertyGroup)
1003 foreach (var relativeProperty in propertyGroup)
1005 if (relativeProperty != property)
1007 var relativeContext = GetOrCreateContext(relativeProperty);
1008 var relativeBinding = relativeContext.Binding;
1010 if (null != relativeBinding)
1013 relativeBinding.Apply(true);
1017 OnPropertyChanged(relativeProperty.PropertyName);
1022 OnPropertyChangedWithData(property);
1026 private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
1027 = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
1030 enum BindableContextAttributes
1032 IsManuallySet = 1 << 0,
1033 IsBeingSet = 1 << 1,
1034 IsDynamicResource = 1 << 2,
1035 IsSetFromStyle = 1 << 3,
1036 IsDefaultValue = 1 << 4,
1037 IsDefaultValueCreated = 1 << 5,
1040 class BindablePropertyContext
1042 public BindableContextAttributes Attributes;
1043 public BindingBase Binding;
1044 public Queue<SetValueArgs> DelayedSetters;
1045 public BindableProperty Property;
1046 public object Value;
1050 internal enum SetValuePrivateFlags
1053 CheckAccess = 1 << 0,
1055 ManuallySet = 1 << 2,
1058 Default = CheckAccess
1063 public readonly SetValueFlags Attributes;
1064 public readonly BindablePropertyContext Context;
1065 public readonly bool CurrentlyApplying;
1066 public readonly BindableProperty Property;
1067 public readonly object Value;
1069 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
1071 Property = property;
1074 CurrentlyApplying = currentlyApplying;
1075 Attributes = attributes;
1079 internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
1081 var xElementToNameOfOld = new Dictionary<object, string>();
1083 foreach (var pair in oldNameScope)
1085 xElementToNameOfOld.Add(pair.Value, pair.Key);
1088 foreach (var property in properties)
1090 if (property.Value.Binding is Binding binding && null != binding.Source)
1093 xElementToNameOfOld.TryGetValue(binding.Source, out xName);
1097 var newObject = newNameScope[xName];
1099 binding.Source = newObject;
1100 SetBinding(property.Key, binding);
1105 if (null != BindingContext)
1108 xElementToNameOfOld.TryGetValue(BindingContext, out xName);
1112 var newObject = newNameScope[xName];
1113 BindingContext = newObject;
1118 internal void ClearBinding()
1120 foreach (var property in properties)
1122 if (null != property.Value.Binding)
1124 property.Value.Binding.Unapply();
1131 namespace Tizen.NUI.Binding.Internals
1134 /// SetValueFlags. For internal use.
1137 [EditorBrowsable(EditorBrowsableState.Never)]
1138 public enum SetValueFlags
1143 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1144 [EditorBrowsable(EditorBrowsableState.Never)]
1148 /// Clear OneWay bindings.
1150 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1151 [EditorBrowsable(EditorBrowsableState.Never)]
1152 ClearOneWayBindings = 1 << 0,
1155 /// Clear TwoWay bindings.
1157 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1158 [EditorBrowsable(EditorBrowsableState.Never)]
1159 ClearTwoWayBindings = 1 << 1,
1162 /// Clear dynamic resource.
1164 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1165 [EditorBrowsable(EditorBrowsableState.Never)]
1166 ClearDynamicResource = 1 << 2,
1171 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1172 [EditorBrowsable(EditorBrowsableState.Never)]
1173 RaiseOnEqual = 1 << 3