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) => SetDynamicResource(property, key, false);
68 /// Raised when a property has changed.
70 /// <since_tizen> 9 </since_tizen>
71 public event PropertyChangedEventHandler PropertyChanged;
73 /// <summary>Copy properties of other ViewStyle to this.</summary>
74 /// <param name="other">The other BindableProperty merge to this.</param>
75 [EditorBrowsable(EditorBrowsableState.Never)]
76 public virtual void CopyFrom(BindableObject other)
78 if (null == other) return;
80 Type type1 = this.GetType();
81 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
83 Type type2 = other.GetType();
84 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
86 if (null != nameToBindableProperty1)
88 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
90 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
92 if (null != bindableProperty && other.IsSet(bindableProperty))
94 object value = other.GetValue(bindableProperty);
95 InternalSetValue(keyValuePair.Value, value);
102 /// Copy all binding from other object.
104 /// <param name="other"></param>
105 [EditorBrowsable(EditorBrowsableState.Never)]
106 public void CopyBindingRelationShip(BindableObject other)
113 foreach (var property in properties)
115 RemoveBinding(property.Key);
118 foreach (var property in other.properties)
120 if (null != property.Value.Binding)
122 var binding = property.Value.Binding;
123 other.RemoveBinding(property.Key);
124 SetBinding(property.Key, binding);
130 /// Raised whenever the BindingContext property changes.
132 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
133 [EditorBrowsable(EditorBrowsableState.Never)]
134 public event EventHandler BindingContextChanged;
136 internal void ClearValue(BindableProperty property, bool fromStyle) => ClearValue(property, fromStyle: fromStyle, checkAccess: true);
139 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
141 /// <param name="property">The BindableProperty to clear</param>
142 internal void ClearValue(BindableProperty property)
144 ClearValue(property, fromStyle: false, checkAccess: true);
148 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
150 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
151 internal void ClearValue(BindablePropertyKey propertyKey)
153 if (propertyKey == null)
154 throw new ArgumentNullException(nameof(propertyKey));
156 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
160 /// Return true if the target property exists and has been set.
162 /// <param name="targetProperty">The target property</param>
163 /// <returns>return true if the target property exists and has been set</returns>
164 internal bool IsSet(BindableProperty targetProperty)
166 if (targetProperty == null)
167 throw new ArgumentNullException(nameof(targetProperty));
169 var bpcontext = GetContext(targetProperty);
170 return bpcontext != null
171 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
175 /// Returns the value that is contained the BindableProperty.
177 /// <param name="property">The BindableProperty for which to get the value.</param>
178 /// <returns>The value that is contained the BindableProperty</returns>
179 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
180 [EditorBrowsable(EditorBrowsableState.Never)]
181 public object GetValue(BindableProperty property)
183 if (property == null)
184 throw new ArgumentNullException(nameof(property));
186 if (!IsBound && property.ValueGetter != null)
188 return property.ValueGetter(this);
191 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
194 return property.DefaultValue;
196 return context.Value;
200 /// Raised when a property is about to change.
202 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
203 [EditorBrowsable(EditorBrowsableState.Never)]
204 public event PropertyChangingEventHandler PropertyChanging;
207 /// Removes a previously set binding.
209 /// <param name="property">The BindableProperty from which to remove bindings.</param>
210 [EditorBrowsable(EditorBrowsableState.Never)]
211 public void RemoveBinding(BindableProperty property)
213 if (property == null)
214 throw new ArgumentNullException(nameof(property));
216 BindablePropertyContext context = GetContext(property);
217 if (context == null || context.Binding == null)
220 RemoveBinding(property, context);
224 /// Assigns a binding to a property.
226 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
227 /// <param name="binding">The binding to set.</param>
228 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
229 [EditorBrowsable(EditorBrowsableState.Never)]
230 public void SetBinding(BindableProperty targetProperty, BindingBase binding) => SetBinding(targetProperty, binding, false);
232 /// Internal used, will never changed to not hidden.
233 [EditorBrowsable(EditorBrowsableState.Never)]
234 public virtual bool IsCreateByXaml
240 /// This will be public opened in next ACR.
241 [EditorBrowsable(EditorBrowsableState.Never)]
242 public void EnforceNotifyBindedInstance(BindableProperty property)
244 if (null != property)
246 BindablePropertyContext context = GetOrCreateContext(property);
247 BindingBase binding = context.Binding;
249 var currentlyApplying = applying;
251 if (binding != null && !currentlyApplying)
258 OnPropertyChanged(property.PropertyName);
260 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
262 if (null != propertyGroup)
264 foreach (var relativeProperty in propertyGroup)
266 if (relativeProperty != property)
268 var relativeContext = GetOrCreateContext(relativeProperty);
269 var relativeBinding = relativeContext.Binding;
271 if (null != relativeBinding)
274 relativeBinding.Apply(true);
278 OnPropertyChanged(relativeProperty.PropertyName);
286 /// Sets the value of the specified property.
288 /// <param name="property">The BindableProperty on which to assign a value.</param>
289 /// <param name="value">The value to set.</param>
290 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
291 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
292 [EditorBrowsable(EditorBrowsableState.Never)]
293 public void SetValue(BindableProperty property, object value)
295 InternalSetValue(property, value);
296 ChangedPropertiesSetExcludingStyle.Add(property);
299 internal void InternalSetValue(BindableProperty property, object value)
303 SetValue(property, value, false, true);
307 if (null == property)
309 throw new ArgumentNullException(nameof(property));
312 object oldvalue = null;
313 BindablePropertyContext context = GetOrCreateContext(property);
316 context.Attributes |= BindableContextAttributes.IsManuallySet;
317 oldvalue = context.Value;
318 context.Value = value;
321 property.PropertyChanging?.Invoke(this, oldvalue, value);
322 property.PropertyChanged?.Invoke(this, oldvalue, value);
324 OnPropertyChanged(property.PropertyName);
325 OnPropertyChangedWithData(property);
329 private HashSet<BindableProperty> changedPropertiesSetExcludingStyle;
330 internal protected HashSet<BindableProperty> ChangedPropertiesSetExcludingStyle
334 if (null == changedPropertiesSetExcludingStyle)
336 changedPropertiesSetExcludingStyle = new HashSet<BindableProperty>();
339 return changedPropertiesSetExcludingStyle;
344 /// Sets the value of the propertyKey.
346 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
347 /// <param name="value">The value to set.</param>
348 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
349 [EditorBrowsable(EditorBrowsableState.Never)]
350 public void SetValue(BindablePropertyKey propertyKey, object value)
352 if (propertyKey == null)
353 throw new ArgumentNullException(nameof(propertyKey));
355 SetValue(propertyKey.BindableProperty, value, false, false);
359 /// Set the inherited context to a neated element.
361 /// <param name="bindable">The object on which to set the inherited binding context.</param>
362 /// <param name="value">The inherited context to set.</param>
363 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
364 [EditorBrowsable(EditorBrowsableState.Never)]
365 public static void SetInheritedBindingContext(BindableObject bindable, object value)
367 if (null == bindable)
369 throw new ArgumentNullException(nameof(bindable));
372 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
373 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
376 object oldContext = bindable.inheritedContext;
378 if (ReferenceEquals(oldContext, value))
381 if (bpContext != null && oldContext == null)
382 oldContext = bpContext.Value;
384 if (bpContext != null && bpContext.Binding != null)
386 bpContext.Binding.Context = value;
387 bindable.inheritedContext = null;
391 bindable.inheritedContext = value;
394 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
395 bindable.OnBindingContextChanged();
399 /// Register the properties which can effect each other in Binding to same group.
401 [EditorBrowsable(EditorBrowsableState.Never)]
402 public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
404 if (!PropertyToGroup.ContainsKey(property))
406 PropertyToGroup.Add(property, group);
409 if (null != group && !(group.Contains(property)))
415 /// Apply the bindings to BindingContext.
417 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
418 [EditorBrowsable(EditorBrowsableState.Never)]
419 protected void ApplyBindings() => ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
422 /// Override this method to execute an action when the BindingContext changes.
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 virtual void OnBindingContextChanged()
428 BindingContextChanged?.Invoke(this, EventArgs.Empty);
432 /// Call this method from a child class to notify that a change happened on a property.
434 /// <param name="propertyName">The name of the property that changed.</param>
435 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
436 [EditorBrowsable(EditorBrowsableState.Never)]
437 protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
438 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
441 /// Call this method from a child class to notify that a change is going to happen on a property.
443 /// <param name="propertyName">The name of the property that is changing.</param>
444 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
445 [EditorBrowsable(EditorBrowsableState.Never)]
446 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
447 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
450 /// Method that is called when a bound property is changed.
452 [EditorBrowsable(EditorBrowsableState.Never)]
453 protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
456 /// Unapplies all previously set bindings.
458 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
459 [EditorBrowsable(EditorBrowsableState.Never)]
460 protected void UnapplyBindings()
462 foreach (var context in properties.Values)
464 if (context.Binding == null)
467 context.Binding.Unapply();
471 internal bool GetIsBound(BindableProperty targetProperty)
473 if (targetProperty == null)
474 throw new ArgumentNullException(nameof(targetProperty));
476 BindablePropertyContext bpcontext = GetContext(targetProperty);
477 return bpcontext != null && bpcontext.Binding != null;
481 /// Returns the value that is contained the BindableProperty.
483 /// <param name="property0">The BindableProperty instance.</param>
484 /// <param name="property1">The BindableProperty instance.</param>
485 /// <returns>The value that is contained the BindableProperty</returns>
486 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
488 var values = new object[2];
490 foreach (var context in properties.Values)
492 if (ReferenceEquals(context.Property, property0))
494 values[0] = context.Value;
497 else if (ReferenceEquals(context.Property, property1))
499 values[1] = context.Value;
503 if (property0 == null && property1 == null)
507 if (!ReferenceEquals(property0, null))
508 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
509 if (!ReferenceEquals(property1, null))
510 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
516 /// Returns the value that is contained the BindableProperty.
518 /// <param name="property0">The BindableProperty instance.</param>
519 /// <param name="property1">The BindableProperty instance.</param>
520 /// <param name="property2">The BindableProperty instance.</param>
521 /// <returns>The value that is contained the BindableProperty</returns>
522 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
524 var values = new object[3];
526 foreach (var context in properties.Values)
528 if (ReferenceEquals(context.Property, property0))
530 values[0] = context.Value;
533 else if (ReferenceEquals(context.Property, property1))
535 values[1] = context.Value;
538 else if (ReferenceEquals(context.Property, property2))
540 values[2] = context.Value;
544 if (property0 == null && property1 == null && property2 == null)
548 if (!ReferenceEquals(property0, null))
549 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
550 if (!ReferenceEquals(property1, null))
551 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
552 if (!ReferenceEquals(property2, null))
553 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
559 /// Returns the value that is contained the BindableProperty.
561 /// <param name="properties">The array of the BindableProperty instances</param>
562 /// <returns>The values that is contained the BindableProperty instances.</returns>
563 internal object[] GetValues(params BindableProperty[] properties)
565 var values = new object[properties.Length];
566 foreach (var context in this.properties.Values)
568 var index = properties.IndexOf(context.Property);
571 values[index] = context.Value;
573 for (var i = 0; i < values.Length; i++)
575 if (!ReferenceEquals(values[i], null))
577 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
582 internal virtual void OnRemoveDynamicResource(BindableProperty property)
586 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
590 internal void RemoveDynamicResource(BindableProperty property)
592 if (property == null)
593 throw new ArgumentNullException(nameof(property));
595 OnRemoveDynamicResource(property);
596 BindablePropertyContext context = GetOrCreateContext(property);
597 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
600 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
602 if (targetProperty == null)
603 throw new ArgumentNullException(nameof(targetProperty));
605 throw new ArgumentNullException(nameof(binding));
607 if (fromStyle && !CanBeSetFromStyle(targetProperty))
612 var context = GetOrCreateContext(targetProperty);
614 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
616 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
618 if (context.Binding != null)
619 context.Binding.Unapply();
621 BindingBase oldBinding = context.Binding;
622 context.Binding = binding;
624 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
626 binding.Apply(BindingContext, this, targetProperty);
629 bool CanBeSetFromStyle(BindableProperty property)
631 var context = GetContext(property);
634 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
636 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
638 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
643 internal void SetDynamicResource(BindableProperty property, string key) => SetDynamicResource(property, key, false);
645 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
647 if (property == null)
648 throw new ArgumentNullException(nameof(property));
649 if (string.IsNullOrEmpty(key))
650 throw new ArgumentNullException(nameof(key));
651 if (fromStyle && !CanBeSetFromStyle(property))
654 var context = GetOrCreateContext(property);
656 context.Attributes |= BindableContextAttributes.IsDynamicResource;
658 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
660 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
662 OnSetDynamicResource(property, key);
665 internal void SetValue(BindableProperty property, object value, bool fromStyle) => SetValue(property, value, fromStyle, true);
667 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
669 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None);
673 /// For internal use.
675 /// <param name="property">The BindableProperty on which to assign a value.</param>
676 /// <param name="value">The value to set</param>
677 /// <param name="attributes">The set value flag</param>
678 [EditorBrowsable(EditorBrowsableState.Never)]
679 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None) => SetValueCore(property, value, attributes, SetValuePrivateFlags.Default);
681 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
683 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
684 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
685 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
686 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
687 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
689 if (property == null)
690 throw new ArgumentNullException(nameof(property));
691 if (checkAccess && property.IsReadOnly)
693 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
697 if (!converted && !property.TryConvert(ref value))
699 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
703 if (property.ValidateValue != null && !property.ValidateValue(this, value))
704 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
706 if (property.CoerceValue != null)
707 value = property.CoerceValue(this, value);
709 BindablePropertyContext context = GetOrCreateContext(property);
712 context.Attributes |= BindableContextAttributes.IsManuallySet;
713 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
717 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
722 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
724 // else omitted on purpose
726 bool currentlyApplying = applying;
728 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
730 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
731 if (delayQueue == null)
732 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
734 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
738 context.Attributes |= BindableContextAttributes.IsBeingSet;
739 SetValueActual(property, context, value, currentlyApplying, attributes, silent);
741 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
742 if (delayQueue != null)
744 while (delayQueue.Count > 0)
746 SetValueArgs s = delayQueue.Dequeue();
747 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, s.Attributes);
750 context.DelayedSetters = null;
753 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
757 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
759 var prop = properties.Values.ToArray();
760 for (int i = 0, propLength = prop.Length; i < propLength; i++)
762 BindablePropertyContext context = prop[i];
763 BindingBase binding = context.Binding;
767 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
770 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
771 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
776 /// Check if object is bound or not.
777 /// This API used for legacy codes.
778 /// Should be removed after all app usage replaced into IsBound.
780 [Obsolete("This has been deprecated in API11. Use IsBound property instead.")]
781 internal bool IsBinded
794 /// Check if object is bound or not.
796 [EditorBrowsable(EditorBrowsableState.Never)]
803 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
805 bindable.inheritedContext = null;
806 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
807 bindable.OnBindingContextChanged();
809 if (newvalue is BindableObject targetBindableObject)
811 targetBindableObject.IsBound = true;
815 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
817 object context = bindable.inheritedContext;
818 var oldBinding = oldBindingBase as Binding;
819 var newBinding = newBindingBase as Binding;
821 if (context == null && oldBinding != null)
822 context = oldBinding.Context;
823 if (context != null && newBinding != null)
824 newBinding.Context = context;
827 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
829 if (property == null)
830 throw new ArgumentNullException(nameof(property));
832 if (checkAccess && property.IsReadOnly)
833 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
835 BindablePropertyContext bpcontext = GetContext(property);
836 if (bpcontext == null)
839 if (fromStyle && !CanBeSetFromStyle(property))
842 object original = bpcontext.Value;
844 object newValue = property.GetDefaultValue(this);
846 bool same = Equals(original, newValue);
849 property.PropertyChanging?.Invoke(this, original, newValue);
851 OnPropertyChanging(property.PropertyName);
854 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
855 bpcontext.Value = newValue;
856 if (property.DefaultValueCreator == null)
857 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
859 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
863 OnPropertyChanged(property.PropertyName);
864 OnPropertyChangedWithData(property);
865 property.PropertyChanged?.Invoke(this, original, newValue);
869 [MethodImpl(MethodImplOptions.AggressiveInlining)]
870 BindablePropertyContext CreateAndAddContext(BindableProperty property)
872 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
874 if (property.DefaultValueCreator == null)
875 context.Attributes = BindableContextAttributes.IsDefaultValue;
877 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
879 properties.Add(property, context);
883 [MethodImpl(MethodImplOptions.AggressiveInlining)]
884 BindablePropertyContext GetContext(BindableProperty property) => properties.TryGetValue(property, out var result) ? result : null;
886 [MethodImpl(MethodImplOptions.AggressiveInlining)]
887 BindablePropertyContext GetOrCreateContext(BindableProperty property)
889 BindablePropertyContext context = GetContext(property);
892 context = CreateAndAddContext(property);
894 else if (property.ValueGetter != null)
896 context.Value = property.ValueGetter(this); //Update Value from dali
897 }//added by xiaohui.fang
898 else if (property.DefaultValueCreator != null) //This will be removed in the future.
900 context.Value = property.DefaultValueCreator(this); //Update Value from dali
906 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
908 context.Binding.Unapply();
910 property.BindingChanging?.Invoke(this, context.Binding, null);
912 context.Binding = null;
915 internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
917 if (property == null)
918 throw new ArgumentNullException(nameof(property));
920 if (checkAccess && property.IsReadOnly)
921 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
923 if (fromStyle && !CanBeSetFromStyle(property))
926 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
927 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0));
930 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, bool silent = false)
932 object original = context.Value;
933 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
934 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
935 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
936 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
938 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
939 if (!silent && (!same || raiseOnEqual))
941 property.PropertyChanging?.Invoke(this, original, value);
943 OnPropertyChanging(property.PropertyName);
946 if (!same || raiseOnEqual)
948 context.Value = value;
951 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
952 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
954 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
955 RemoveDynamicResource(property);
957 BindingBase binding = context.Binding;
960 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
962 RemoveBinding(property, context);
967 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
969 if (!silent && (!same || raiseOnEqual))
971 property.PropertyChanged?.Invoke(this, original, value);
973 if (binding != null && !currentlyApplying)
980 OnPropertyChanged(property.PropertyName);
982 if (null != propertyGroup)
984 foreach (var relativeProperty in propertyGroup)
986 if (relativeProperty != property)
988 var relativeContext = GetOrCreateContext(relativeProperty);
989 var relativeBinding = relativeContext.Binding;
991 if (null != relativeBinding)
994 relativeBinding.Apply(true);
998 OnPropertyChanged(relativeProperty.PropertyName);
1003 OnPropertyChangedWithData(property);
1007 private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
1008 = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
1011 enum BindableContextAttributes
1013 IsManuallySet = 1 << 0,
1014 IsBeingSet = 1 << 1,
1015 IsDynamicResource = 1 << 2,
1016 IsSetFromStyle = 1 << 3,
1017 IsDefaultValue = 1 << 4,
1018 IsDefaultValueCreated = 1 << 5,
1021 class BindablePropertyContext
1023 public BindableContextAttributes Attributes;
1024 public BindingBase Binding;
1025 public Queue<SetValueArgs> DelayedSetters;
1026 public BindableProperty Property;
1027 public object Value;
1031 internal enum SetValuePrivateFlags
1034 CheckAccess = 1 << 0,
1036 ManuallySet = 1 << 2,
1039 Default = CheckAccess
1044 public readonly SetValueFlags Attributes;
1045 public readonly BindablePropertyContext Context;
1046 public readonly bool CurrentlyApplying;
1047 public readonly BindableProperty Property;
1048 public readonly object Value;
1050 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
1052 Property = property;
1055 CurrentlyApplying = currentlyApplying;
1056 Attributes = attributes;
1060 internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
1062 var xElementToNameOfOld = new Dictionary<object, string>();
1064 foreach (var pair in oldNameScope)
1066 xElementToNameOfOld.Add(pair.Value, pair.Key);
1069 foreach (var property in properties)
1071 if (property.Value.Binding is Binding binding && null != binding.Source)
1074 xElementToNameOfOld.TryGetValue(binding.Source, out xName);
1078 var newObject = newNameScope[xName];
1080 binding.Source = newObject;
1081 SetBinding(property.Key, binding);
1086 if (null != BindingContext)
1089 xElementToNameOfOld.TryGetValue(BindingContext, out xName);
1093 var newObject = newNameScope[xName];
1094 BindingContext = newObject;
1100 /// Unapplies all previously set bindings.
1102 [EditorBrowsable(EditorBrowsableState.Never)]
1103 public void ClearBinding()
1105 foreach (var property in properties)
1107 if (null != property.Value.Binding)
1109 property.Value.Binding.Unapply();
1116 namespace Tizen.NUI.Binding.Internals
1119 /// SetValueFlags. For internal use.
1122 [EditorBrowsable(EditorBrowsableState.Never)]
1123 public enum SetValueFlags
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)]
1133 /// Clear OneWay bindings.
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 ClearOneWayBindings = 1 << 0,
1140 /// Clear TwoWay bindings.
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 ClearTwoWayBindings = 1 << 1,
1147 /// Clear dynamic resource.
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 ClearDynamicResource = 1 << 2,
1156 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1157 [EditorBrowsable(EditorBrowsableState.Never)]
1158 RaiseOnEqual = 1 << 3