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 && other.IsSet(bindableProperty))
99 object value = other.GetValue(bindableProperty);
100 InternalSetValue(keyValuePair.Value, value);
107 /// Copy all binding from other object.
109 /// <param name="other"></param>
110 [EditorBrowsable(EditorBrowsableState.Never)]
111 public void CopyBindingRelationShip(BindableObject other)
118 foreach (var property in properties)
120 RemoveBinding(property.Key);
123 foreach (var property in other.properties)
125 if (null != property.Value.Binding)
127 var binding = property.Value.Binding;
128 other.RemoveBinding(property.Key);
129 SetBinding(property.Key, binding);
135 /// Raised whenever the BindingContext property changes.
137 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
138 [EditorBrowsable(EditorBrowsableState.Never)]
139 public event EventHandler BindingContextChanged;
141 internal void ClearValue(BindableProperty property, bool fromStyle)
143 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
147 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
149 /// <param name="property">The BindableProperty to clear</param>
150 internal void ClearValue(BindableProperty property)
152 ClearValue(property, fromStyle: false, checkAccess: true);
156 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
158 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
159 internal void ClearValue(BindablePropertyKey propertyKey)
161 if (propertyKey == null)
162 throw new ArgumentNullException(nameof(propertyKey));
164 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
168 /// Return true if the target property exists and has been set.
170 /// <param name="targetProperty">The target property</param>
171 /// <returns>return true if the target property exists and has been set</returns>
172 internal bool IsSet(BindableProperty targetProperty)
174 if (targetProperty == null)
175 throw new ArgumentNullException(nameof(targetProperty));
177 var bpcontext = GetContext(targetProperty);
178 return bpcontext != null
179 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
183 /// Returns the value that is contained the BindableProperty.
185 /// <param name="property">The BindableProperty for which to get the value.</param>
186 /// <returns>The value that is contained the BindableProperty</returns>
187 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
188 [EditorBrowsable(EditorBrowsableState.Never)]
189 public object GetValue(BindableProperty property)
191 if (property == null)
192 throw new ArgumentNullException(nameof(property));
194 if (!IsBinded && property.ValueGetter != null)
196 return property.ValueGetter(this);
199 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
202 return property.DefaultValue;
204 return context.Value;
208 /// Raised when a property is about to change.
210 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
211 [EditorBrowsable(EditorBrowsableState.Never)]
212 public event PropertyChangingEventHandler PropertyChanging;
215 /// Removes a previously set binding.
217 /// <param name="property">The BindableProperty from which to remove bindings.</param>
218 internal void RemoveBinding(BindableProperty property)
220 if (property == null)
221 throw new ArgumentNullException(nameof(property));
223 BindablePropertyContext context = GetContext(property);
224 if (context == null || context.Binding == null)
227 RemoveBinding(property, context);
231 /// Assigns a binding to a property.
233 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
234 /// <param name="binding">The binding to set.</param>
235 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
236 [EditorBrowsable(EditorBrowsableState.Never)]
237 public void SetBinding(BindableProperty targetProperty, BindingBase binding)
239 SetBinding(targetProperty, binding, false);
242 /// Internal used, will never changed to not hidden.
243 [EditorBrowsable(EditorBrowsableState.Never)]
244 public virtual bool IsCreateByXaml
250 /// This will be public opened in next ACR.
251 [EditorBrowsable(EditorBrowsableState.Never)]
252 public void EnforceNotifyBindedInstance(BindableProperty property)
254 if (null != property)
256 BindablePropertyContext context = GetOrCreateContext(property);
257 BindingBase binding = context.Binding;
259 var currentlyApplying = applying;
261 if (binding != null && !currentlyApplying)
268 OnPropertyChanged(property.PropertyName);
270 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
272 if (null != propertyGroup)
274 foreach (var relativeProperty in propertyGroup)
276 if (relativeProperty != property)
278 var relativeContext = GetOrCreateContext(relativeProperty);
279 var relativeBinding = relativeContext.Binding;
281 if (null != relativeBinding)
284 relativeBinding.Apply(true);
288 OnPropertyChanged(relativeProperty.PropertyName);
296 /// Sets the value of the specified property.
298 /// <param name="property">The BindableProperty on which to assign a value.</param>
299 /// <param name="value">The value to set.</param>
300 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
301 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
302 [EditorBrowsable(EditorBrowsableState.Never)]
303 public void SetValue(BindableProperty property, object value)
305 InternalSetValue(property, value);
306 ChangedPropertiesSetExcludingStyle.Add(property);
309 internal void InternalSetValue(BindableProperty property, object value)
311 if (true == IsBinded)
313 SetValue(property, value, false, true);
317 if (null == property)
319 throw new ArgumentNullException(nameof(property));
322 object oldvalue = null;
323 BindablePropertyContext context = GetOrCreateContext(property);
326 context.Attributes |= BindableContextAttributes.IsManuallySet;
327 oldvalue = context.Value;
328 context.Value = value;
331 property.PropertyChanged?.Invoke(this, oldvalue, value);
333 OnPropertyChanged(property.PropertyName);
334 OnPropertyChangedWithData(property);
338 private HashSet<BindableProperty> changedPropertiesSetExcludingStyle;
339 internal protected HashSet<BindableProperty> ChangedPropertiesSetExcludingStyle
343 if (null == changedPropertiesSetExcludingStyle)
345 changedPropertiesSetExcludingStyle = new HashSet<BindableProperty>();
348 return changedPropertiesSetExcludingStyle;
353 /// Sets the value of the propertyKey.
355 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
356 /// <param name="value">The value to set.</param>
357 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
358 [EditorBrowsable(EditorBrowsableState.Never)]
359 public void SetValue(BindablePropertyKey propertyKey, object value)
361 if (propertyKey == null)
362 throw new ArgumentNullException(nameof(propertyKey));
364 SetValue(propertyKey.BindableProperty, value, false, false);
368 /// Set the inherited context to a neated element.
370 /// <param name="bindable">The object on which to set the inherited binding context.</param>
371 /// <param name="value">The inherited context to set.</param>
372 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
373 [EditorBrowsable(EditorBrowsableState.Never)]
374 public static void SetInheritedBindingContext(BindableObject bindable, object value)
376 if (null == bindable)
378 throw new ArgumentNullException(nameof(bindable));
381 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
382 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
385 object oldContext = bindable.inheritedContext;
387 if (ReferenceEquals(oldContext, value))
390 if (bpContext != null && oldContext == null)
391 oldContext = bpContext.Value;
393 if (bpContext != null && bpContext.Binding != null)
395 bpContext.Binding.Context = value;
396 bindable.inheritedContext = null;
400 bindable.inheritedContext = value;
403 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
404 bindable.OnBindingContextChanged();
408 /// Register the properties which can effect each other in Binding to same group.
410 [EditorBrowsable(EditorBrowsableState.Never)]
411 public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
413 if (!PropertyToGroup.ContainsKey(property))
415 PropertyToGroup.Add(property, group);
418 if (null != group && !(group.Contains(property)))
424 /// Apply the bindings to BindingContext.
426 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
427 [EditorBrowsable(EditorBrowsableState.Never)]
428 protected void ApplyBindings()
430 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
434 /// Override this method to execute an action when the BindingContext changes.
436 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
437 [EditorBrowsable(EditorBrowsableState.Never)]
438 protected virtual void OnBindingContextChanged()
440 BindingContextChanged?.Invoke(this, EventArgs.Empty);
444 /// Call this method from a child class to notify that a change happened on a property.
446 /// <param name="propertyName">The name of the property that changed.</param>
447 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
448 [EditorBrowsable(EditorBrowsableState.Never)]
449 protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
450 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
453 /// Call this method from a child class to notify that a change is going to happen on a property.
455 /// <param name="propertyName">The name of the property that is changing.</param>
456 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
457 [EditorBrowsable(EditorBrowsableState.Never)]
458 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
459 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
462 /// Method that is called when a bound property is changed.
464 [EditorBrowsable(EditorBrowsableState.Never)]
465 protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
468 /// Unapplies all previously set bindings.
470 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
471 [EditorBrowsable(EditorBrowsableState.Never)]
472 protected void UnapplyBindings()
474 foreach (var context in properties.Values)
476 if (context.Binding == null)
479 context.Binding.Unapply();
483 internal bool GetIsBound(BindableProperty targetProperty)
485 if (targetProperty == null)
486 throw new ArgumentNullException(nameof(targetProperty));
488 BindablePropertyContext bpcontext = GetContext(targetProperty);
489 return bpcontext != null && bpcontext.Binding != null;
493 /// Returns the value that is contained the BindableProperty.
495 /// <param name="property0">The BindableProperty instance.</param>
496 /// <param name="property1">The BindableProperty instance.</param>
497 /// <returns>The value that is contained the BindableProperty</returns>
498 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
500 var values = new object[2];
502 foreach (var context in properties.Values)
504 if (ReferenceEquals(context.Property, property0))
506 values[0] = context.Value;
509 else if (ReferenceEquals(context.Property, property1))
511 values[1] = context.Value;
515 if (property0 == null && property1 == null)
519 if (!ReferenceEquals(property0, null))
520 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
521 if (!ReferenceEquals(property1, null))
522 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
528 /// Returns the value that is contained the BindableProperty.
530 /// <param name="property0">The BindableProperty instance.</param>
531 /// <param name="property1">The BindableProperty instance.</param>
532 /// <param name="property2">The BindableProperty instance.</param>
533 /// <returns>The value that is contained the BindableProperty</returns>
534 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
536 var values = new object[3];
538 foreach (var context in properties.Values)
540 if (ReferenceEquals(context.Property, property0))
542 values[0] = context.Value;
545 else if (ReferenceEquals(context.Property, property1))
547 values[1] = context.Value;
550 else if (ReferenceEquals(context.Property, property2))
552 values[2] = context.Value;
556 if (property0 == null && property1 == null && property2 == null)
560 if (!ReferenceEquals(property0, null))
561 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
562 if (!ReferenceEquals(property1, null))
563 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
564 if (!ReferenceEquals(property2, null))
565 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
571 /// Returns the value that is contained the BindableProperty.
573 /// <param name="properties">The array of the BindableProperty instances</param>
574 /// <returns>The values that is contained the BindableProperty instances.</returns>
575 internal object[] GetValues(params BindableProperty[] properties)
577 var values = new object[properties.Length];
578 foreach (var context in this.properties.Values)
580 var index = properties.IndexOf(context.Property);
583 values[index] = context.Value;
585 for (var i = 0; i < values.Length; i++)
587 if (!ReferenceEquals(values[i], null))
589 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
594 internal virtual void OnRemoveDynamicResource(BindableProperty property)
598 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
602 internal void RemoveDynamicResource(BindableProperty property)
604 if (property == null)
605 throw new ArgumentNullException(nameof(property));
607 OnRemoveDynamicResource(property);
608 BindablePropertyContext context = GetOrCreateContext(property);
609 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
612 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
614 if (targetProperty == null)
615 throw new ArgumentNullException(nameof(targetProperty));
617 throw new ArgumentNullException(nameof(binding));
619 if (fromStyle && !CanBeSetFromStyle(targetProperty))
624 var context = GetOrCreateContext(targetProperty);
626 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
628 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
630 if (context.Binding != null)
631 context.Binding.Unapply();
633 BindingBase oldBinding = context.Binding;
634 context.Binding = binding;
636 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
638 binding.Apply(BindingContext, this, targetProperty);
641 bool CanBeSetFromStyle(BindableProperty property)
643 var context = GetContext(property);
646 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
648 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
650 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
655 internal void SetDynamicResource(BindableProperty property, string key)
657 SetDynamicResource(property, key, false);
660 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
662 if (property == null)
663 throw new ArgumentNullException(nameof(property));
664 if (string.IsNullOrEmpty(key))
665 throw new ArgumentNullException(nameof(key));
666 if (fromStyle && !CanBeSetFromStyle(property))
669 var context = GetOrCreateContext(property);
671 context.Attributes |= BindableContextAttributes.IsDynamicResource;
673 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
675 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
677 OnSetDynamicResource(property, key);
680 internal void SetValue(BindableProperty property, object value, bool fromStyle)
682 SetValue(property, value, fromStyle, true);
685 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
687 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None);
691 /// For internal use.
693 /// <param name="property">The BindableProperty on which to assign a value.</param>
694 /// <param name="value">The value to set</param>
695 /// <param name="attributes">The set value flag</param>
696 [EditorBrowsable(EditorBrowsableState.Never)]
697 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
699 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default);
702 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
704 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
705 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
706 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
707 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
708 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
710 if (property == null)
711 throw new ArgumentNullException(nameof(property));
712 if (checkAccess && property.IsReadOnly)
714 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
718 if (!converted && !property.TryConvert(ref value))
720 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
724 if (property.ValidateValue != null && !property.ValidateValue(this, value))
725 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
727 if (property.CoerceValue != null)
728 value = property.CoerceValue(this, value);
730 BindablePropertyContext context = GetOrCreateContext(property);
733 context.Attributes |= BindableContextAttributes.IsManuallySet;
734 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
738 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
743 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
745 // else omitted on purpose
747 bool currentlyApplying = applying;
749 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
751 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
752 if (delayQueue == null)
753 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
755 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
759 context.Attributes |= BindableContextAttributes.IsBeingSet;
760 SetValueActual(property, context, value, currentlyApplying, attributes, silent);
762 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
763 if (delayQueue != null)
765 while (delayQueue.Count > 0)
767 SetValueArgs s = delayQueue.Dequeue();
768 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, s.Attributes);
771 context.DelayedSetters = null;
774 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
778 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
780 var prop = properties.Values.ToArray();
781 for (int i = 0, propLength = prop.Length; i < propLength; i++)
783 BindablePropertyContext context = prop[i];
784 BindingBase binding = context.Binding;
788 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
791 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
792 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
796 internal bool IsBinded
802 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
804 bindable.inheritedContext = null;
805 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
806 bindable.OnBindingContextChanged();
808 if (newvalue is BindableObject targetBindableObject)
810 targetBindableObject.IsBinded = true;
814 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
816 object context = bindable.inheritedContext;
817 var oldBinding = oldBindingBase as Binding;
818 var newBinding = newBindingBase as Binding;
820 if (context == null && oldBinding != null)
821 context = oldBinding.Context;
822 if (context != null && newBinding != null)
823 newBinding.Context = context;
826 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
828 if (property == null)
829 throw new ArgumentNullException(nameof(property));
831 if (checkAccess && property.IsReadOnly)
832 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
834 BindablePropertyContext bpcontext = GetContext(property);
835 if (bpcontext == null)
838 if (fromStyle && !CanBeSetFromStyle(property))
841 object original = bpcontext.Value;
843 object newValue = property.GetDefaultValue(this);
845 bool same = Equals(original, newValue);
848 property.PropertyChanging?.Invoke(this, original, newValue);
850 OnPropertyChanging(property.PropertyName);
853 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
854 bpcontext.Value = newValue;
855 if (property.DefaultValueCreator == null)
856 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
858 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
862 OnPropertyChanged(property.PropertyName);
863 OnPropertyChangedWithData(property);
864 property.PropertyChanged?.Invoke(this, original, newValue);
868 [MethodImpl(MethodImplOptions.AggressiveInlining)]
869 BindablePropertyContext CreateAndAddContext(BindableProperty property)
871 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
873 if (property.DefaultValueCreator == null)
874 context.Attributes = BindableContextAttributes.IsDefaultValue;
876 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
878 properties.Add(property, context);
882 [MethodImpl(MethodImplOptions.AggressiveInlining)]
883 BindablePropertyContext GetContext(BindableProperty property) => properties.TryGetValue(property, out var result) ? result : null;
885 [MethodImpl(MethodImplOptions.AggressiveInlining)]
886 BindablePropertyContext GetOrCreateContext(BindableProperty property)
888 BindablePropertyContext context = GetContext(property);
891 context = CreateAndAddContext(property);
893 else if (property.ValueGetter != null)
895 context.Value = property.ValueGetter(this); //Update Value from dali
896 }//added by xiaohui.fang
897 else if (property.DefaultValueCreator != null) //This will be removed in the future.
899 context.Value = property.DefaultValueCreator(this); //Update Value from dali
905 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
907 context.Binding.Unapply();
909 property.BindingChanging?.Invoke(this, context.Binding, null);
911 context.Binding = null;
914 internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
916 if (property == null)
917 throw new ArgumentNullException(nameof(property));
919 if (checkAccess && property.IsReadOnly)
920 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
922 if (fromStyle && !CanBeSetFromStyle(property))
925 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
926 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0));
929 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, bool silent = false)
931 object original = context.Value;
932 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
933 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
934 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
935 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
937 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
938 if (!silent && (!same || raiseOnEqual))
940 property.PropertyChanging?.Invoke(this, original, value);
942 OnPropertyChanging(property.PropertyName);
945 if (!same || raiseOnEqual)
947 context.Value = value;
950 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
951 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
953 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
954 RemoveDynamicResource(property);
956 BindingBase binding = context.Binding;
959 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
961 RemoveBinding(property, context);
966 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
968 if (!silent && (!same || raiseOnEqual))
970 property.PropertyChanged?.Invoke(this, original, value);
972 if (binding != null && !currentlyApplying)
979 OnPropertyChanged(property.PropertyName);
981 if (null != propertyGroup)
983 foreach (var relativeProperty in propertyGroup)
985 if (relativeProperty != property)
987 var relativeContext = GetOrCreateContext(relativeProperty);
988 var relativeBinding = relativeContext.Binding;
990 if (null != relativeBinding)
993 relativeBinding.Apply(true);
997 OnPropertyChanged(relativeProperty.PropertyName);
1002 OnPropertyChangedWithData(property);
1006 private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
1007 = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
1010 enum BindableContextAttributes
1012 IsManuallySet = 1 << 0,
1013 IsBeingSet = 1 << 1,
1014 IsDynamicResource = 1 << 2,
1015 IsSetFromStyle = 1 << 3,
1016 IsDefaultValue = 1 << 4,
1017 IsDefaultValueCreated = 1 << 5,
1020 class BindablePropertyContext
1022 public BindableContextAttributes Attributes;
1023 public BindingBase Binding;
1024 public Queue<SetValueArgs> DelayedSetters;
1025 public BindableProperty Property;
1026 public object Value;
1030 internal enum SetValuePrivateFlags
1033 CheckAccess = 1 << 0,
1035 ManuallySet = 1 << 2,
1038 Default = CheckAccess
1043 public readonly SetValueFlags Attributes;
1044 public readonly BindablePropertyContext Context;
1045 public readonly bool CurrentlyApplying;
1046 public readonly BindableProperty Property;
1047 public readonly object Value;
1049 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
1051 Property = property;
1054 CurrentlyApplying = currentlyApplying;
1055 Attributes = attributes;
1059 internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
1061 var xElementToNameOfOld = new Dictionary<object, string>();
1063 foreach (var pair in oldNameScope)
1065 xElementToNameOfOld.Add(pair.Value, pair.Key);
1068 foreach (var property in properties)
1070 if (property.Value.Binding is Binding binding && null != binding.Source)
1073 xElementToNameOfOld.TryGetValue(binding.Source, out xName);
1077 var newObject = newNameScope[xName];
1079 binding.Source = newObject;
1080 SetBinding(property.Key, binding);
1085 if (null != BindingContext)
1088 xElementToNameOfOld.TryGetValue(BindingContext, out xName);
1092 var newObject = newNameScope[xName];
1093 BindingContext = newObject;
1098 internal void ClearBinding()
1100 foreach (var property in properties)
1102 if (null != property.Value.Binding)
1104 property.Value.Binding.Unapply();
1111 namespace Tizen.NUI.Binding.Internals
1114 /// SetValueFlags. For internal use.
1117 [EditorBrowsable(EditorBrowsableState.Never)]
1118 public enum SetValueFlags
1123 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1124 [EditorBrowsable(EditorBrowsableState.Never)]
1128 /// Clear OneWay bindings.
1130 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1131 [EditorBrowsable(EditorBrowsableState.Never)]
1132 ClearOneWayBindings = 1 << 0,
1135 /// Clear TwoWay bindings.
1137 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1138 [EditorBrowsable(EditorBrowsableState.Never)]
1139 ClearTwoWayBindings = 1 << 1,
1142 /// Clear dynamic resource.
1144 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1145 [EditorBrowsable(EditorBrowsableState.Never)]
1146 ClearDynamicResource = 1 << 2,
1151 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1152 [EditorBrowsable(EditorBrowsableState.Never)]
1153 RaiseOnEqual = 1 << 3