2 * Copyright(c) 2021 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), null, propertyChanged: (BindableProperty.BindingPropertyChangedDelegate)((bindable, oldValue, newValue) =>
42 var bindableObject = (BindableObject)bindable;
45 bindableObject.bindingContext = newValue;
46 bindableObject.FlushBinding();
48 if (newValue is BindableObject targetBindableObject)
50 targetBindableObject.IsBinded = true;
54 defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
56 if (null != bindable.bindingContext)
58 return bindable.bindingContext;
61 if (bindable is Container container)
63 return container.Parent?.BindingContext;
71 readonly Dictionary<BindableProperty, BindablePropertyContext> properties = new Dictionary<BindableProperty, BindablePropertyContext>(4);
74 object inheritedContext;
76 private object bindingContext;
79 /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
81 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
82 [EditorBrowsable(EditorBrowsableState.Never)]
83 public object BindingContext
85 get { return inheritedContext ?? GetValue(BindingContextProperty); }
86 set { SetValue(BindingContextProperty, value); }
89 void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
91 SetDynamicResource(property, key, false);
95 /// Raised when a property has changed.
97 /// <since_tizen> 9 </since_tizen>
98 public event PropertyChangedEventHandler PropertyChanged;
100 /// <summary>Copy properties of other ViewStyle to this.</summary>
101 /// <param name="other">The other BindableProperty merge to this.</param>
102 [EditorBrowsable(EditorBrowsableState.Never)]
103 public virtual void CopyFrom(BindableObject other)
105 if (null == other) return;
107 Type type1 = this.GetType();
108 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
110 Type type2 = other.GetType();
111 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
113 if (null != nameToBindableProperty1)
115 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
117 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
119 if (null != bindableProperty && (SettedPropeties.Contains(bindableProperty) || other.SettedPropeties.Contains(bindableProperty)))
121 object value = other.GetValue(bindableProperty);
125 SetValue(keyValuePair.Value, value);
133 /// Copy all binding from other object.
135 /// <param name="other"></param>
136 [EditorBrowsable(EditorBrowsableState.Never)]
137 public void CopyBindingRelationShip(BindableObject other)
144 foreach (var property in properties)
146 RemoveBinding(property.Key);
149 foreach (var property in other.properties)
151 if (null != property.Value.Binding)
153 var binding = property.Value.Binding;
154 other.RemoveBinding(property.Key);
155 SetBinding(property.Key, binding);
161 /// Raised whenever the BindingContext property changes.
163 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
164 [EditorBrowsable(EditorBrowsableState.Never)]
165 public event EventHandler BindingContextChanged;
167 internal void ClearValue(BindableProperty property, bool fromStyle)
169 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
173 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
175 /// <param name="property">The BindableProperty to clear</param>
176 internal void ClearValue(BindableProperty property)
178 ClearValue(property, fromStyle: false, checkAccess: true);
182 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
184 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
185 internal void ClearValue(BindablePropertyKey propertyKey)
187 if (propertyKey == null)
188 throw new ArgumentNullException(nameof(propertyKey));
190 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
194 /// Return true if the target property exists and has been set.
196 /// <param name="targetProperty">The target property</param>
197 /// <returns>return true if the target property exists and has been set</returns>
198 internal bool IsSet(BindableProperty targetProperty)
200 if (targetProperty == null)
201 throw new ArgumentNullException(nameof(targetProperty));
203 var bpcontext = GetContext(targetProperty);
204 return bpcontext != null
205 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
209 /// Returns the value that is contained the BindableProperty.
211 /// <param name="property">The BindableProperty for which to get the value.</param>
212 /// <returns>The value that is contained the BindableProperty</returns>
213 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
214 [EditorBrowsable(EditorBrowsableState.Never)]
215 public object GetValue(BindableProperty property)
217 if (property == null)
218 throw new ArgumentNullException(nameof(property));
220 if (!IsBinded && property.ValueGetter != null)
222 return property.ValueGetter(this);
225 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
228 return property.DefaultValue;
230 return context.Value;
234 /// Raised when a property is about to change.
236 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
237 [EditorBrowsable(EditorBrowsableState.Never)]
238 public event PropertyChangingEventHandler PropertyChanging;
241 /// Removes a previously set binding.
243 /// <param name="property">The BindableProperty from which to remove bindings.</param>
244 internal void RemoveBinding(BindableProperty property)
246 if (property == null)
247 throw new ArgumentNullException(nameof(property));
249 BindablePropertyContext context = GetContext(property);
250 if (context == null || context.Binding == null)
253 RemoveBinding(property, context);
257 /// Assigns a binding to a property.
259 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
260 /// <param name="binding">The binding to set.</param>
261 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
262 [EditorBrowsable(EditorBrowsableState.Never)]
263 public void SetBinding(BindableProperty targetProperty, BindingBase binding)
265 SetBinding(targetProperty, binding, false);
268 private bool isCreateByXaml = false;
269 /// Only used by the IL of xaml, will never changed to not hidden.
270 [EditorBrowsable(EditorBrowsableState.Never)]
271 public virtual bool IsCreateByXaml
275 return isCreateByXaml;
279 isCreateByXaml = value;
284 /// Sets the value of the specified property.
286 /// <param name="property">The BindableProperty on which to assign a value.</param>
287 /// <param name="value">The value to set.</param>
288 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
289 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
290 [EditorBrowsable(EditorBrowsableState.Never)]
291 public void SetValue(BindableProperty property, object value)
293 if (true == IsBinded)
295 SetValue(property, value, false, true);
299 if (null == property)
301 throw new ArgumentNullException(nameof(property));
304 object oldvalue = null;
305 if (null == property.DefaultValueCreator)
307 BindablePropertyContext context = GetOrCreateContext(property);
310 oldvalue = context.Value;
311 context.Value = value;
316 oldvalue = property.DefaultValueCreator.Invoke(this);
319 property.PropertyChanged?.Invoke(this, oldvalue, value);
321 OnPropertyChanged(property.PropertyName);
322 OnPropertyChangedWithData(property);
325 SettedPropeties.Add(property);
328 private HashSet<BindableProperty> settedPropeties;
329 private HashSet<BindableProperty> SettedPropeties
333 if (null == settedPropeties)
335 settedPropeties = new HashSet<BindableProperty>();
338 return settedPropeties;
342 internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
344 if (property == null)
345 throw new ArgumentNullException(nameof(property));
347 if (true == isCreateByXaml)
349 if (property.IsReadOnly)
350 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
352 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
353 SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
357 property.PropertyChanged?.Invoke(this, null, value);
362 /// Sets the value of the propertyKey.
364 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
365 /// <param name="value">The value to set.</param>
366 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
367 [EditorBrowsable(EditorBrowsableState.Never)]
368 public void SetValue(BindablePropertyKey propertyKey, object value)
370 if (propertyKey == null)
371 throw new ArgumentNullException(nameof(propertyKey));
373 SetValue(propertyKey.BindableProperty, value, false, false);
377 /// Set the inherited context to a neated element.
379 /// <param name="bindable">The object on which to set the inherited binding context.</param>
380 /// <param name="value">The inherited context to set.</param>
381 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
382 [EditorBrowsable(EditorBrowsableState.Never)]
383 public static void SetInheritedBindingContext(BindableObject bindable, object value)
385 if (null == bindable)
387 throw new ArgumentNullException(nameof(bindable));
390 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
391 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
394 object oldContext = bindable.inheritedContext;
396 if (ReferenceEquals(oldContext, value))
399 if (bpContext != null && oldContext == null)
400 oldContext = bpContext.Value;
402 if (bpContext != null && bpContext.Binding != null)
404 bpContext.Binding.Context = value;
405 bindable.inheritedContext = null;
409 bindable.inheritedContext = value;
412 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
413 bindable.OnBindingContextChanged();
417 /// Register the properties which can effect each other in Binding to same group.
419 [EditorBrowsable(EditorBrowsableState.Never)]
420 public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
422 if (!PropertyToGroup.ContainsKey(property))
424 PropertyToGroup.Add(property, group);
427 if (null != group && !(group.Contains(property)))
433 /// Apply the bindings to BindingContext.
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 void ApplyBindings()
439 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
443 /// Override this method to execute an action when the BindingContext changes.
445 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
446 [EditorBrowsable(EditorBrowsableState.Never)]
447 protected virtual void OnBindingContextChanged()
449 BindingContextChanged?.Invoke(this, EventArgs.Empty);
453 /// Call this method from a child class to notify that a change happened on a property.
455 /// <param name="propertyName">The name of the property that changed.</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 OnPropertyChanged([CallerMemberName] string propertyName = null)
459 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
462 /// Call this method from a child class to notify that a change is going to happen on a property.
464 /// <param name="propertyName">The name of the property that is changing.</param>
465 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
466 [EditorBrowsable(EditorBrowsableState.Never)]
467 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
468 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
471 /// Method that is called when a bound property is changed.
473 [EditorBrowsable(EditorBrowsableState.Never)]
474 protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
477 /// Unapplies all previously set bindings.
479 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
480 [EditorBrowsable(EditorBrowsableState.Never)]
481 protected void UnapplyBindings()
483 foreach (var context in properties.Values)
485 if (context.Binding == null)
488 context.Binding.Unapply();
492 internal bool GetIsBound(BindableProperty targetProperty)
494 if (targetProperty == null)
495 throw new ArgumentNullException(nameof(targetProperty));
497 BindablePropertyContext bpcontext = GetContext(targetProperty);
498 return bpcontext != null && bpcontext.Binding != null;
502 /// Returns the value that is contained the BindableProperty.
504 /// <param name="property0">The BindableProperty instance.</param>
505 /// <param name="property1">The BindableProperty instance.</param>
506 /// <returns>The value that is contained the BindableProperty</returns>
507 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
509 var values = new object[2];
511 foreach (var context in properties.Values)
513 if (ReferenceEquals(context.Property, property0))
515 values[0] = context.Value;
518 else if (ReferenceEquals(context.Property, property1))
520 values[1] = context.Value;
524 if (property0 == null && property1 == null)
528 if (!ReferenceEquals(property0, null))
529 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
530 if (!ReferenceEquals(property1, null))
531 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
537 /// Returns the value that is contained the BindableProperty.
539 /// <param name="property0">The BindableProperty instance.</param>
540 /// <param name="property1">The BindableProperty instance.</param>
541 /// <param name="property2">The BindableProperty instance.</param>
542 /// <returns>The value that is contained the BindableProperty</returns>
543 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
545 var values = new object[3];
547 foreach (var context in properties.Values)
549 if (ReferenceEquals(context.Property, property0))
551 values[0] = context.Value;
554 else if (ReferenceEquals(context.Property, property1))
556 values[1] = context.Value;
559 else if (ReferenceEquals(context.Property, property2))
561 values[2] = context.Value;
565 if (property0 == null && property1 == null && property2 == null)
569 if (!ReferenceEquals(property0, null))
570 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
571 if (!ReferenceEquals(property1, null))
572 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
573 if (!ReferenceEquals(property2, null))
574 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
580 /// Returns the value that is contained the BindableProperty.
582 /// <param name="properties">The array of the BindableProperty instances</param>
583 /// <returns>The values that is contained the BindableProperty instances.</returns>
584 internal object[] GetValues(params BindableProperty[] properties)
586 var values = new object[properties.Length];
587 foreach (var context in this.properties.Values)
589 var index = properties.IndexOf(context.Property);
592 values[index] = context.Value;
594 for (var i = 0; i < values.Length; i++)
596 if (!ReferenceEquals(values[i], null))
598 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
603 internal virtual void OnRemoveDynamicResource(BindableProperty property)
607 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
611 internal void RemoveDynamicResource(BindableProperty property)
613 if (property == null)
614 throw new ArgumentNullException(nameof(property));
616 OnRemoveDynamicResource(property);
617 BindablePropertyContext context = GetOrCreateContext(property);
618 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
621 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
623 if (targetProperty == null)
624 throw new ArgumentNullException(nameof(targetProperty));
626 throw new ArgumentNullException(nameof(binding));
628 if (fromStyle && !CanBeSetFromStyle(targetProperty))
633 var context = GetOrCreateContext(targetProperty);
635 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
637 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
639 if (context.Binding != null)
640 context.Binding.Unapply();
642 BindingBase oldBinding = context.Binding;
643 context.Binding = binding;
645 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
647 binding.Apply(BindingContext, this, targetProperty);
650 bool CanBeSetFromStyle(BindableProperty property)
652 var context = GetContext(property);
655 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
657 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
659 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
664 internal void SetDynamicResource(BindableProperty property, string key)
666 SetDynamicResource(property, key, false);
669 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
671 if (property == null)
672 throw new ArgumentNullException(nameof(property));
673 if (string.IsNullOrEmpty(key))
674 throw new ArgumentNullException(nameof(key));
675 if (fromStyle && !CanBeSetFromStyle(property))
678 var context = GetOrCreateContext(property);
680 context.Attributes |= BindableContextAttributes.IsDynamicResource;
682 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
684 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
686 OnSetDynamicResource(property, key);
689 internal void SetValue(BindableProperty property, object value, bool fromStyle)
691 SetValue(property, value, fromStyle, true);
694 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
696 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
700 /// For internal use.
702 /// <param name="property">The BindableProperty on which to assign a value.</param>
703 /// <param name="value">The value to set</param>
704 /// <param name="attributes">The set value flag</param>
705 [EditorBrowsable(EditorBrowsableState.Never)]
706 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
708 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
711 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
713 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
714 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
715 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
716 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
717 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
719 if (property == null)
720 throw new ArgumentNullException(nameof(property));
721 if (checkAccess && property.IsReadOnly)
723 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
727 if (!converted && !property.TryConvert(ref value))
729 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
733 if (property.ValidateValue != null && !property.ValidateValue(this, value))
734 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
736 if (property.CoerceValue != null)
737 value = property.CoerceValue(this, value);
739 BindablePropertyContext context = GetOrCreateContext(property);
742 context.Attributes |= BindableContextAttributes.IsManuallySet;
743 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
747 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
752 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
754 // else omitted on purpose
756 bool currentlyApplying = applying;
758 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
760 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
761 if (delayQueue == null)
762 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
764 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
768 context.Attributes |= BindableContextAttributes.IsBeingSet;
769 SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
771 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
772 if (delayQueue != null)
774 while (delayQueue.Count > 0)
776 SetValueArgs s = delayQueue.Dequeue();
777 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
780 context.DelayedSetters = null;
783 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
787 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
789 var prop = properties.Values.ToArray();
790 for (int i = 0, propLength = prop.Length; i < propLength; i++)
792 BindablePropertyContext context = prop[i];
793 BindingBase binding = context.Binding;
797 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
800 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
801 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
805 internal bool IsBinded
811 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
813 object context = bindable.inheritedContext;
814 var oldBinding = oldBindingBase as Binding;
815 var newBinding = newBindingBase as Binding;
817 if (context == null && oldBinding != null)
818 context = oldBinding.Context;
819 if (context != null && newBinding != null)
820 newBinding.Context = context;
823 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
825 if (property == null)
826 throw new ArgumentNullException(nameof(property));
828 if (checkAccess && property.IsReadOnly)
829 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
831 BindablePropertyContext bpcontext = GetContext(property);
832 if (bpcontext == null)
835 if (fromStyle && !CanBeSetFromStyle(property))
838 object original = bpcontext.Value;
840 object newValue = property.GetDefaultValue(this);
842 bool same = Equals(original, newValue);
845 property.PropertyChanging?.Invoke(this, original, newValue);
847 OnPropertyChanging(property.PropertyName);
850 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
851 bpcontext.Value = newValue;
852 if (property.DefaultValueCreator == null)
853 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
855 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
859 OnPropertyChanged(property.PropertyName);
860 OnPropertyChangedWithData(property);
861 property.PropertyChanged?.Invoke(this, original, newValue);
865 [MethodImpl(MethodImplOptions.AggressiveInlining)]
866 BindablePropertyContext CreateAndAddContext(BindableProperty property)
868 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
870 if (property.DefaultValueCreator == null)
871 context.Attributes = BindableContextAttributes.IsDefaultValue;
873 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
875 properties.Add(property, context);
879 [MethodImpl(MethodImplOptions.AggressiveInlining)]
880 BindablePropertyContext GetContext(BindableProperty property) => properties.TryGetValue(property, out var result) ? result : null;
882 [MethodImpl(MethodImplOptions.AggressiveInlining)]
883 BindablePropertyContext GetOrCreateContext(BindableProperty property)
885 BindablePropertyContext context = GetContext(property);
888 context = CreateAndAddContext(property);
890 else if (property.ValueGetter != null)
892 context.Value = property.ValueGetter(this); //Update Value from dali
893 }//added by xiaohui.fang
894 else if (property.DefaultValueCreator != null) //This will be removed in the future.
896 context.Value = property.DefaultValueCreator(this); //Update Value from dali
902 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
904 context.Binding.Unapply();
906 property.BindingChanging?.Invoke(this, context.Binding, null);
908 context.Binding = null;
911 internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
913 if (property == null)
914 throw new ArgumentNullException(nameof(property));
916 if (checkAccess && property.IsReadOnly)
917 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
919 if (fromStyle && !CanBeSetFromStyle(property))
922 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
923 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
927 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
929 object original = context.Value;
930 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
931 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
932 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
933 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
935 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
936 if (!silent && (!same || raiseOnEqual))
938 property.PropertyChanging?.Invoke(this, original, value);
940 OnPropertyChanging(property.PropertyName);
943 if (!same || raiseOnEqual)
945 context.Value = value;
948 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
949 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
951 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
952 RemoveDynamicResource(property);
954 BindingBase binding = context.Binding;
957 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
959 RemoveBinding(property, context);
964 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
968 if ((!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 else if (true == same && true == forceSendChangeSignal)
1004 if (binding != null && !currentlyApplying)
1007 binding.Apply(true);
1011 OnPropertyChanged(property.PropertyName);
1013 if (null != propertyGroup)
1015 foreach (var relativeProperty in propertyGroup)
1017 if (relativeProperty != property)
1019 var relativeContext = GetOrCreateContext(relativeProperty);
1020 var relativeBinding = relativeContext.Binding;
1022 if (null != relativeBinding)
1025 relativeBinding.Apply(true);
1029 OnPropertyChanged(relativeProperty.PropertyName);
1035 OnPropertyChangedWithData(property);
1039 private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
1040 = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
1043 enum BindableContextAttributes
1045 IsManuallySet = 1 << 0,
1046 IsBeingSet = 1 << 1,
1047 IsDynamicResource = 1 << 2,
1048 IsSetFromStyle = 1 << 3,
1049 IsDefaultValue = 1 << 4,
1050 IsDefaultValueCreated = 1 << 5,
1053 class BindablePropertyContext
1055 public BindableContextAttributes Attributes;
1056 public BindingBase Binding;
1057 public Queue<SetValueArgs> DelayedSetters;
1058 public BindableProperty Property;
1059 public object Value;
1063 internal enum SetValuePrivateFlags
1066 CheckAccess = 1 << 0,
1068 ManuallySet = 1 << 2,
1071 Default = CheckAccess
1076 public readonly SetValueFlags Attributes;
1077 public readonly BindablePropertyContext Context;
1078 public readonly bool CurrentlyApplying;
1079 public readonly BindableProperty Property;
1080 public readonly object Value;
1082 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
1084 Property = property;
1087 CurrentlyApplying = currentlyApplying;
1088 Attributes = attributes;
1092 internal void AddChildBindableObject(BindableObject child)
1096 children.Add(child);
1097 child.FlushBinding();
1101 internal void RemoveChildBindableObject(BindableObject child)
1103 children.Remove(child);
1106 internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
1108 var xElementToNameOfOld = new Dictionary<object, string>();
1110 foreach (var pair in oldNameScope)
1112 xElementToNameOfOld.Add(pair.Value, pair.Key);
1115 foreach (var property in properties)
1117 if (property.Value.Binding is Binding binding && null != binding.Source)
1120 xElementToNameOfOld.TryGetValue(binding.Source, out xName);
1124 var newObject = newNameScope[xName];
1126 binding.Source = newObject;
1127 SetBinding(property.Key, binding);
1132 if (null != BindingContext)
1135 xElementToNameOfOld.TryGetValue(BindingContext, out xName);
1139 var newObject = newNameScope[xName];
1140 BindingContext = newObject;
1145 internal void ClearBinding()
1147 foreach (var property in properties)
1149 if (null != property.Value.Binding)
1151 property.Value.Binding.Unapply();
1156 private List<BindableObject> children = new List<BindableObject>();
1158 private void FlushBinding()
1160 ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
1161 OnBindingContextChanged();
1163 foreach (var child in children)
1165 child.FlushBinding();
1171 namespace Tizen.NUI.Binding.Internals
1174 /// SetValueFlags. For internal use.
1177 [EditorBrowsable(EditorBrowsableState.Never)]
1178 public enum SetValueFlags
1183 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1184 [EditorBrowsable(EditorBrowsableState.Never)]
1188 /// Clear OneWay bindings.
1190 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1191 [EditorBrowsable(EditorBrowsableState.Never)]
1192 ClearOneWayBindings = 1 << 0,
1195 /// Clear TwoWay bindings.
1197 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1198 [EditorBrowsable(EditorBrowsableState.Never)]
1199 ClearTwoWayBindings = 1 << 1,
1202 /// Clear dynamic resource.
1204 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1205 [EditorBrowsable(EditorBrowsableState.Never)]
1206 ClearDynamicResource = 1 << 2,
1211 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1212 [EditorBrowsable(EditorBrowsableState.Never)]
1213 RaiseOnEqual = 1 << 3