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;
48 private object bindingContext;
51 /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
53 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
54 [EditorBrowsable(EditorBrowsableState.Never)]
55 public object BindingContext
57 get { return inheritedContext ?? GetValue(BindingContextProperty); }
58 set { SetValue(BindingContextProperty, value); }
61 [EditorBrowsable(EditorBrowsableState.Never)]
62 public int LineNumber { get; set; } = -1;
64 [EditorBrowsable(EditorBrowsableState.Never)]
65 public int LinePosition { get; set; } = -1;
67 void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
69 SetDynamicResource(property, key, false);
73 /// Raised when a property has changed.
75 /// <since_tizen> 9 </since_tizen>
76 public event PropertyChangedEventHandler PropertyChanged;
78 /// <summary>Copy properties of other ViewStyle to this.</summary>
79 /// <param name="other">The other BindableProperty merge to this.</param>
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 public virtual void CopyFrom(BindableObject other)
83 if (null == other) return;
85 Type type1 = this.GetType();
86 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
88 Type type2 = other.GetType();
89 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
91 if (null != nameToBindableProperty1)
93 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
95 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
97 if (null != bindableProperty && (ChangedPropertiesSet.Contains(bindableProperty) || other.ChangedPropertiesSet.Contains(bindableProperty)))
99 object value = other.GetValue(bindableProperty);
103 InternalSetValue(keyValuePair.Value, value);
111 /// Copy all binding from other object.
113 /// <param name="other"></param>
114 [EditorBrowsable(EditorBrowsableState.Never)]
115 public void CopyBindingRelationShip(BindableObject other)
122 foreach (var property in properties)
124 RemoveBinding(property.Key);
127 foreach (var property in other.properties)
129 if (null != property.Value.Binding)
131 var binding = property.Value.Binding;
132 other.RemoveBinding(property.Key);
133 SetBinding(property.Key, binding);
139 /// Raised whenever the BindingContext property changes.
141 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
142 [EditorBrowsable(EditorBrowsableState.Never)]
143 public event EventHandler BindingContextChanged;
145 internal void ClearValue(BindableProperty property, bool fromStyle)
147 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
151 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
153 /// <param name="property">The BindableProperty to clear</param>
154 internal void ClearValue(BindableProperty property)
156 ClearValue(property, fromStyle: false, checkAccess: true);
160 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
162 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
163 internal void ClearValue(BindablePropertyKey propertyKey)
165 if (propertyKey == null)
166 throw new ArgumentNullException(nameof(propertyKey));
168 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
172 /// Return true if the target property exists and has been set.
174 /// <param name="targetProperty">The target property</param>
175 /// <returns>return true if the target property exists and has been set</returns>
176 internal bool IsSet(BindableProperty targetProperty)
178 if (targetProperty == null)
179 throw new ArgumentNullException(nameof(targetProperty));
181 var bpcontext = GetContext(targetProperty);
182 return bpcontext != null
183 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
187 /// Returns the value that is contained the BindableProperty.
189 /// <param name="property">The BindableProperty for which to get the value.</param>
190 /// <returns>The value that is contained the BindableProperty</returns>
191 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
192 [EditorBrowsable(EditorBrowsableState.Never)]
193 public object GetValue(BindableProperty property)
195 if (property == null)
196 throw new ArgumentNullException(nameof(property));
198 if (!IsBinded && property.ValueGetter != null)
200 return property.ValueGetter(this);
203 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
206 return property.DefaultValue;
208 return context.Value;
212 /// Raised when a property is about to change.
214 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
215 [EditorBrowsable(EditorBrowsableState.Never)]
216 public event PropertyChangingEventHandler PropertyChanging;
219 /// Removes a previously set binding.
221 /// <param name="property">The BindableProperty from which to remove bindings.</param>
222 internal void RemoveBinding(BindableProperty property)
224 if (property == null)
225 throw new ArgumentNullException(nameof(property));
227 BindablePropertyContext context = GetContext(property);
228 if (context == null || context.Binding == null)
231 RemoveBinding(property, context);
235 /// Assigns a binding to a property.
237 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
238 /// <param name="binding">The binding to set.</param>
239 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
240 [EditorBrowsable(EditorBrowsableState.Never)]
241 public void SetBinding(BindableProperty targetProperty, BindingBase binding)
243 SetBinding(targetProperty, binding, false);
246 private bool isCreateByXaml = false;
247 /// Only used by the IL of xaml, will never changed to not hidden.
248 [EditorBrowsable(EditorBrowsableState.Never)]
249 public virtual bool IsCreateByXaml
253 return isCreateByXaml;
257 isCreateByXaml = value;
262 /// Sets the value of the specified property.
264 /// <param name="property">The BindableProperty on which to assign a value.</param>
265 /// <param name="value">The value to set.</param>
266 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
267 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
268 [EditorBrowsable(EditorBrowsableState.Never)]
269 public void SetValue(BindableProperty property, object value)
271 InternalSetValue(property, value);
272 ChangedPropertiesSetExcludingStyle.Add(property);
275 internal void InternalSetValue(BindableProperty property, object value)
277 if (true == IsBinded)
279 SetValue(property, value, false, true);
283 if (null == property)
285 throw new ArgumentNullException(nameof(property));
288 object oldvalue = null;
289 if (null == property.DefaultValueCreator)
291 BindablePropertyContext context = GetOrCreateContext(property);
294 oldvalue = context.Value;
295 context.Value = value;
300 oldvalue = property.DefaultValueCreator.Invoke(this);
303 property.PropertyChanged?.Invoke(this, oldvalue, value);
305 OnPropertyChanged(property.PropertyName);
306 OnPropertyChangedWithData(property);
309 ChangedPropertiesSet.Add(property);
312 private HashSet<BindableProperty> changedPropertiesSet;
313 private HashSet<BindableProperty> ChangedPropertiesSet
317 if (null == changedPropertiesSet)
319 changedPropertiesSet = new HashSet<BindableProperty>();
322 return changedPropertiesSet;
326 private HashSet<BindableProperty> changedPropertiesSetExcludingStyle;
327 internal protected HashSet<BindableProperty> ChangedPropertiesSetExcludingStyle
331 if (null == changedPropertiesSetExcludingStyle)
333 changedPropertiesSetExcludingStyle = new HashSet<BindableProperty>();
336 return changedPropertiesSetExcludingStyle;
340 internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
342 if (property == null)
343 throw new ArgumentNullException(nameof(property));
345 if (true == isCreateByXaml)
347 if (property.IsReadOnly)
348 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
350 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
351 SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
355 property.PropertyChanged?.Invoke(this, null, value);
360 /// Sets the value of the propertyKey.
362 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
363 /// <param name="value">The value to set.</param>
364 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
365 [EditorBrowsable(EditorBrowsableState.Never)]
366 public void SetValue(BindablePropertyKey propertyKey, object value)
368 if (propertyKey == null)
369 throw new ArgumentNullException(nameof(propertyKey));
371 SetValue(propertyKey.BindableProperty, value, false, false);
375 /// Set the inherited context to a neated element.
377 /// <param name="bindable">The object on which to set the inherited binding context.</param>
378 /// <param name="value">The inherited context to set.</param>
379 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
380 [EditorBrowsable(EditorBrowsableState.Never)]
381 public static void SetInheritedBindingContext(BindableObject bindable, object value)
383 if (null == bindable)
385 throw new ArgumentNullException(nameof(bindable));
388 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
389 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
392 object oldContext = bindable.inheritedContext;
394 if (ReferenceEquals(oldContext, value))
397 if (bpContext != null && oldContext == null)
398 oldContext = bpContext.Value;
400 if (bpContext != null && bpContext.Binding != null)
402 bpContext.Binding.Context = value;
403 bindable.inheritedContext = null;
407 bindable.inheritedContext = value;
410 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
411 bindable.OnBindingContextChanged();
415 /// Register the properties which can effect each other in Binding to same group.
417 [EditorBrowsable(EditorBrowsableState.Never)]
418 public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
420 if (!PropertyToGroup.ContainsKey(property))
422 PropertyToGroup.Add(property, group);
425 if (null != group && !(group.Contains(property)))
431 /// Apply the bindings to BindingContext.
433 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
434 [EditorBrowsable(EditorBrowsableState.Never)]
435 protected void ApplyBindings()
437 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
441 /// Override this method to execute an action when the BindingContext changes.
443 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
444 [EditorBrowsable(EditorBrowsableState.Never)]
445 protected virtual void OnBindingContextChanged()
447 BindingContextChanged?.Invoke(this, EventArgs.Empty);
451 /// Call this method from a child class to notify that a change happened on a property.
453 /// <param name="propertyName">The name of the property that changed.</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 OnPropertyChanged([CallerMemberName] string propertyName = null)
457 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
460 /// Call this method from a child class to notify that a change is going to happen on a property.
462 /// <param name="propertyName">The name of the property that is changing.</param>
463 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
464 [EditorBrowsable(EditorBrowsableState.Never)]
465 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
466 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
469 /// Method that is called when a bound property is changed.
471 [EditorBrowsable(EditorBrowsableState.Never)]
472 protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
475 /// Unapplies all previously set bindings.
477 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
478 [EditorBrowsable(EditorBrowsableState.Never)]
479 protected void UnapplyBindings()
481 foreach (var context in properties.Values)
483 if (context.Binding == null)
486 context.Binding.Unapply();
490 internal bool GetIsBound(BindableProperty targetProperty)
492 if (targetProperty == null)
493 throw new ArgumentNullException(nameof(targetProperty));
495 BindablePropertyContext bpcontext = GetContext(targetProperty);
496 return bpcontext != null && bpcontext.Binding != null;
500 /// Returns the value that is contained the BindableProperty.
502 /// <param name="property0">The BindableProperty instance.</param>
503 /// <param name="property1">The BindableProperty instance.</param>
504 /// <returns>The value that is contained the BindableProperty</returns>
505 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
507 var values = new object[2];
509 foreach (var context in properties.Values)
511 if (ReferenceEquals(context.Property, property0))
513 values[0] = context.Value;
516 else if (ReferenceEquals(context.Property, property1))
518 values[1] = context.Value;
522 if (property0 == null && property1 == null)
526 if (!ReferenceEquals(property0, null))
527 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
528 if (!ReferenceEquals(property1, null))
529 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
535 /// Returns the value that is contained the BindableProperty.
537 /// <param name="property0">The BindableProperty instance.</param>
538 /// <param name="property1">The BindableProperty instance.</param>
539 /// <param name="property2">The BindableProperty instance.</param>
540 /// <returns>The value that is contained the BindableProperty</returns>
541 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
543 var values = new object[3];
545 foreach (var context in properties.Values)
547 if (ReferenceEquals(context.Property, property0))
549 values[0] = context.Value;
552 else if (ReferenceEquals(context.Property, property1))
554 values[1] = context.Value;
557 else if (ReferenceEquals(context.Property, property2))
559 values[2] = context.Value;
563 if (property0 == null && property1 == null && property2 == null)
567 if (!ReferenceEquals(property0, null))
568 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
569 if (!ReferenceEquals(property1, null))
570 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
571 if (!ReferenceEquals(property2, null))
572 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
578 /// Returns the value that is contained the BindableProperty.
580 /// <param name="properties">The array of the BindableProperty instances</param>
581 /// <returns>The values that is contained the BindableProperty instances.</returns>
582 internal object[] GetValues(params BindableProperty[] properties)
584 var values = new object[properties.Length];
585 foreach (var context in this.properties.Values)
587 var index = properties.IndexOf(context.Property);
590 values[index] = context.Value;
592 for (var i = 0; i < values.Length; i++)
594 if (!ReferenceEquals(values[i], null))
596 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
601 internal virtual void OnRemoveDynamicResource(BindableProperty property)
605 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
609 internal void RemoveDynamicResource(BindableProperty property)
611 if (property == null)
612 throw new ArgumentNullException(nameof(property));
614 OnRemoveDynamicResource(property);
615 BindablePropertyContext context = GetOrCreateContext(property);
616 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
619 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
621 if (targetProperty == null)
622 throw new ArgumentNullException(nameof(targetProperty));
624 throw new ArgumentNullException(nameof(binding));
626 if (fromStyle && !CanBeSetFromStyle(targetProperty))
631 var context = GetOrCreateContext(targetProperty);
633 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
635 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
637 if (context.Binding != null)
638 context.Binding.Unapply();
640 BindingBase oldBinding = context.Binding;
641 context.Binding = binding;
643 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
645 binding.Apply(BindingContext, this, targetProperty);
648 bool CanBeSetFromStyle(BindableProperty property)
650 var context = GetContext(property);
653 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
655 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
657 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
662 internal void SetDynamicResource(BindableProperty property, string key)
664 SetDynamicResource(property, key, false);
667 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
669 if (property == null)
670 throw new ArgumentNullException(nameof(property));
671 if (string.IsNullOrEmpty(key))
672 throw new ArgumentNullException(nameof(key));
673 if (fromStyle && !CanBeSetFromStyle(property))
676 var context = GetOrCreateContext(property);
678 context.Attributes |= BindableContextAttributes.IsDynamicResource;
680 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
682 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
684 OnSetDynamicResource(property, key);
687 internal void SetValue(BindableProperty property, object value, bool fromStyle)
689 SetValue(property, value, fromStyle, true);
692 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
694 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
698 /// For internal use.
700 /// <param name="property">The BindableProperty on which to assign a value.</param>
701 /// <param name="value">The value to set</param>
702 /// <param name="attributes">The set value flag</param>
703 [EditorBrowsable(EditorBrowsableState.Never)]
704 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
706 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
709 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
711 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
712 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
713 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
714 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
715 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
717 if (property == null)
718 throw new ArgumentNullException(nameof(property));
719 if (checkAccess && property.IsReadOnly)
721 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
725 if (!converted && !property.TryConvert(ref value))
727 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
731 if (property.ValidateValue != null && !property.ValidateValue(this, value))
732 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
734 if (property.CoerceValue != null)
735 value = property.CoerceValue(this, value);
737 BindablePropertyContext context = GetOrCreateContext(property);
740 context.Attributes |= BindableContextAttributes.IsManuallySet;
741 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
745 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
750 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
752 // else omitted on purpose
754 bool currentlyApplying = applying;
756 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
758 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
759 if (delayQueue == null)
760 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
762 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
766 context.Attributes |= BindableContextAttributes.IsBeingSet;
767 SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
769 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
770 if (delayQueue != null)
772 while (delayQueue.Count > 0)
774 SetValueArgs s = delayQueue.Dequeue();
775 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
778 context.DelayedSetters = null;
781 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
785 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
787 var prop = properties.Values.ToArray();
788 for (int i = 0, propLength = prop.Length; i < propLength; i++)
790 BindablePropertyContext context = prop[i];
791 BindingBase binding = context.Binding;
795 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
798 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
799 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
803 internal bool IsBinded
809 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
811 bindable.inheritedContext = null;
812 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
813 bindable.OnBindingContextChanged();
815 if (newvalue is BindableObject targetBindableObject)
817 targetBindableObject.IsBinded = true;
821 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
823 object context = bindable.inheritedContext;
824 var oldBinding = oldBindingBase as Binding;
825 var newBinding = newBindingBase as Binding;
827 if (context == null && oldBinding != null)
828 context = oldBinding.Context;
829 if (context != null && newBinding != null)
830 newBinding.Context = context;
833 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
835 if (property == null)
836 throw new ArgumentNullException(nameof(property));
838 if (checkAccess && property.IsReadOnly)
839 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
841 BindablePropertyContext bpcontext = GetContext(property);
842 if (bpcontext == null)
845 if (fromStyle && !CanBeSetFromStyle(property))
848 object original = bpcontext.Value;
850 object newValue = property.GetDefaultValue(this);
852 bool same = Equals(original, newValue);
855 property.PropertyChanging?.Invoke(this, original, newValue);
857 OnPropertyChanging(property.PropertyName);
860 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
861 bpcontext.Value = newValue;
862 if (property.DefaultValueCreator == null)
863 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
865 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
869 OnPropertyChanged(property.PropertyName);
870 OnPropertyChangedWithData(property);
871 property.PropertyChanged?.Invoke(this, original, newValue);
875 [MethodImpl(MethodImplOptions.AggressiveInlining)]
876 BindablePropertyContext CreateAndAddContext(BindableProperty property)
878 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
880 if (property.DefaultValueCreator == null)
881 context.Attributes = BindableContextAttributes.IsDefaultValue;
883 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
885 properties.Add(property, context);
889 [MethodImpl(MethodImplOptions.AggressiveInlining)]
890 BindablePropertyContext GetContext(BindableProperty property) => properties.TryGetValue(property, out var result) ? result : null;
892 [MethodImpl(MethodImplOptions.AggressiveInlining)]
893 BindablePropertyContext GetOrCreateContext(BindableProperty property)
895 BindablePropertyContext context = GetContext(property);
898 context = CreateAndAddContext(property);
900 else if (property.ValueGetter != null)
902 context.Value = property.ValueGetter(this); //Update Value from dali
903 }//added by xiaohui.fang
904 else if (property.DefaultValueCreator != null) //This will be removed in the future.
906 context.Value = property.DefaultValueCreator(this); //Update Value from dali
912 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
914 context.Binding.Unapply();
916 property.BindingChanging?.Invoke(this, context.Binding, null);
918 context.Binding = null;
921 internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
923 if (property == null)
924 throw new ArgumentNullException(nameof(property));
926 if (checkAccess && property.IsReadOnly)
927 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
929 if (fromStyle && !CanBeSetFromStyle(property))
932 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
933 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
937 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
939 object original = context.Value;
940 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
941 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
942 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
943 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
945 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
946 if (!silent && (!same || raiseOnEqual))
948 property.PropertyChanging?.Invoke(this, original, value);
950 OnPropertyChanging(property.PropertyName);
953 if (!same || raiseOnEqual)
955 context.Value = value;
958 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
959 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
961 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
962 RemoveDynamicResource(property);
964 BindingBase binding = context.Binding;
967 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
969 RemoveBinding(property, context);
974 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
978 if ((!same || raiseOnEqual))
980 property.PropertyChanged?.Invoke(this, original, value);
982 if (binding != null && !currentlyApplying)
989 OnPropertyChanged(property.PropertyName);
991 if (null != propertyGroup)
993 foreach (var relativeProperty in propertyGroup)
995 if (relativeProperty != property)
997 var relativeContext = GetOrCreateContext(relativeProperty);
998 var relativeBinding = relativeContext.Binding;
1000 if (null != relativeBinding)
1003 relativeBinding.Apply(true);
1007 OnPropertyChanged(relativeProperty.PropertyName);
1012 else if (true == same && true == forceSendChangeSignal)
1014 if (binding != null && !currentlyApplying)
1017 binding.Apply(true);
1021 OnPropertyChanged(property.PropertyName);
1023 if (null != propertyGroup)
1025 foreach (var relativeProperty in propertyGroup)
1027 if (relativeProperty != property)
1029 var relativeContext = GetOrCreateContext(relativeProperty);
1030 var relativeBinding = relativeContext.Binding;
1032 if (null != relativeBinding)
1035 relativeBinding.Apply(true);
1039 OnPropertyChanged(relativeProperty.PropertyName);
1045 OnPropertyChangedWithData(property);
1049 private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
1050 = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
1053 enum BindableContextAttributes
1055 IsManuallySet = 1 << 0,
1056 IsBeingSet = 1 << 1,
1057 IsDynamicResource = 1 << 2,
1058 IsSetFromStyle = 1 << 3,
1059 IsDefaultValue = 1 << 4,
1060 IsDefaultValueCreated = 1 << 5,
1063 class BindablePropertyContext
1065 public BindableContextAttributes Attributes;
1066 public BindingBase Binding;
1067 public Queue<SetValueArgs> DelayedSetters;
1068 public BindableProperty Property;
1069 public object Value;
1073 internal enum SetValuePrivateFlags
1076 CheckAccess = 1 << 0,
1078 ManuallySet = 1 << 2,
1081 Default = CheckAccess
1086 public readonly SetValueFlags Attributes;
1087 public readonly BindablePropertyContext Context;
1088 public readonly bool CurrentlyApplying;
1089 public readonly BindableProperty Property;
1090 public readonly object Value;
1092 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
1094 Property = property;
1097 CurrentlyApplying = currentlyApplying;
1098 Attributes = attributes;
1102 internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
1104 var xElementToNameOfOld = new Dictionary<object, string>();
1106 foreach (var pair in oldNameScope)
1108 xElementToNameOfOld.Add(pair.Value, pair.Key);
1111 foreach (var property in properties)
1113 if (property.Value.Binding is Binding binding && null != binding.Source)
1116 xElementToNameOfOld.TryGetValue(binding.Source, out xName);
1120 var newObject = newNameScope[xName];
1122 binding.Source = newObject;
1123 SetBinding(property.Key, binding);
1128 if (null != BindingContext)
1131 xElementToNameOfOld.TryGetValue(BindingContext, out xName);
1135 var newObject = newNameScope[xName];
1136 BindingContext = newObject;
1141 internal void ClearBinding()
1143 foreach (var property in properties)
1145 if (null != property.Value.Binding)
1147 property.Value.Binding.Unapply();
1154 namespace Tizen.NUI.Binding.Internals
1157 /// SetValueFlags. For internal use.
1160 [EditorBrowsable(EditorBrowsableState.Never)]
1161 public enum SetValueFlags
1166 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1167 [EditorBrowsable(EditorBrowsableState.Never)]
1171 /// Clear OneWay bindings.
1173 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1174 [EditorBrowsable(EditorBrowsableState.Never)]
1175 ClearOneWayBindings = 1 << 0,
1178 /// Clear TwoWay bindings.
1180 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1181 [EditorBrowsable(EditorBrowsableState.Never)]
1182 ClearTwoWayBindings = 1 << 1,
1185 /// Clear dynamic resource.
1187 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1188 [EditorBrowsable(EditorBrowsableState.Never)]
1189 ClearDynamicResource = 1 << 2,
1194 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1195 [EditorBrowsable(EditorBrowsableState.Never)]
1196 RaiseOnEqual = 1 << 3