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;
23 using System.Runtime.CompilerServices;
24 using Tizen.NUI.Binding.Internals;
26 namespace Tizen.NUI.Binding
29 /// Provides a mechanism by which application developers can propagate changes that are made to data in one object to another.
31 /// <since_tizen> 9 </since_tizen>
32 public abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
35 /// Implements the bound property whose interface is provided by the BindingContext property.
37 [EditorBrowsable(EditorBrowsableState.Never)]
38 public static readonly BindableProperty BindingContextProperty =
39 BindableProperty.Create(nameof(BindingContext), typeof(object), typeof(BindableObject), default(object), BindingMode.OneWay, null, BindingContextPropertyChanged,
40 null, null, BindingContextPropertyBindingChanging);
42 readonly List<BindablePropertyContext> properties = new List<BindablePropertyContext>(4);
45 object inheritedContext;
47 private object bindingContext;
50 /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
52 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
53 [EditorBrowsable(EditorBrowsableState.Never)]
54 public object BindingContext
56 get { return inheritedContext ?? GetValue(BindingContextProperty); }
57 set { SetValue(BindingContextProperty, value); }
60 [EditorBrowsable(EditorBrowsableState.Never)]
61 public int LineNumber { get; set; } = -1;
63 [EditorBrowsable(EditorBrowsableState.Never)]
64 public int LinePosition { get; set; } = -1;
66 void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
68 SetDynamicResource(property, key, false);
72 /// Raised when a property has changed.
74 /// <since_tizen> 9 </since_tizen>
75 public event PropertyChangedEventHandler PropertyChanged;
77 /// <summary>Copy properties of other ViewStyle to this.</summary>
78 /// <param name="other">The other BindableProperty merge to this.</param>
79 [EditorBrowsable(EditorBrowsableState.Never)]
80 public virtual void CopyFrom(BindableObject other)
82 if (null == other) return;
84 Type type1 = this.GetType();
85 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
87 Type type2 = other.GetType();
88 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
90 if (null != nameToBindableProperty1)
92 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
94 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
96 if (null != bindableProperty)
98 object value = other.GetValue(bindableProperty);
102 SetValue(keyValuePair.Value, value);
110 /// Raised whenever the BindingContext property changes.
112 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
113 [EditorBrowsable(EditorBrowsableState.Never)]
114 public event EventHandler BindingContextChanged;
116 internal void ClearValue(BindableProperty property, bool fromStyle)
118 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
122 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
124 /// <param name="property">The BindableProperty to clear</param>
125 internal void ClearValue(BindableProperty property)
127 ClearValue(property, fromStyle: false, checkAccess: true);
131 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
133 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
134 internal void ClearValue(BindablePropertyKey propertyKey)
136 if (propertyKey == null)
137 throw new ArgumentNullException(nameof(propertyKey));
139 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
143 /// Return true if the target property exists and has been set.
145 /// <param name="targetProperty">The target property</param>
146 /// <returns>return true if the target property exists and has been set</returns>
147 internal bool IsSet(BindableProperty targetProperty)
149 if (targetProperty == null)
150 throw new ArgumentNullException(nameof(targetProperty));
152 var bpcontext = GetContext(targetProperty);
153 return bpcontext != null
154 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
158 /// Returns the value that is contained the BindableProperty.
160 /// <param name="property">The BindableProperty for which to get the value.</param>
161 /// <returns>The value that is contained the BindableProperty</returns>
162 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
163 [EditorBrowsable(EditorBrowsableState.Never)]
164 public object GetValue(BindableProperty property)
166 if (property == null)
167 throw new ArgumentNullException(nameof(property));
169 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
172 return property.DefaultValue;
174 return context.Value;
178 /// Raised when a property is about to change.
180 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
181 [EditorBrowsable(EditorBrowsableState.Never)]
182 public event PropertyChangingEventHandler PropertyChanging;
185 /// Removes a previously set binding.
187 /// <param name="property">The BindableProperty from which to remove bindings.</param>
188 internal void RemoveBinding(BindableProperty property)
190 if (property == null)
191 throw new ArgumentNullException(nameof(property));
193 BindablePropertyContext context = GetContext(property);
194 if (context == null || context.Binding == null)
197 RemoveBinding(property, context);
201 /// Assigns a binding to a property.
203 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
204 /// <param name="binding">The binding to set.</param>
205 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
206 [EditorBrowsable(EditorBrowsableState.Never)]
207 public void SetBinding(BindableProperty targetProperty, BindingBase binding)
209 SetBinding(targetProperty, binding, false);
212 /// Only used by the IL of xaml, will never changed to not hidden.
213 [EditorBrowsable(EditorBrowsableState.Never)]
214 public virtual bool IsCreateByXaml
220 /// This will be public opened in next ACR.
221 [EditorBrowsable(EditorBrowsableState.Never)]
222 public void EnforceNotifyBindedInstance(BindableProperty property)
224 if (null != property)
226 BindablePropertyContext context = GetOrCreateContext(property);
227 BindingBase binding = context.Binding;
229 var currentlyApplying = applying;
231 if (binding != null && !currentlyApplying)
238 OnPropertyChanged(property.PropertyName);
240 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
242 if (null != propertyGroup)
244 foreach (var relativeProperty in propertyGroup)
246 if (relativeProperty != property)
248 var relativeContext = GetOrCreateContext(relativeProperty);
249 var relativeBinding = relativeContext.Binding;
251 if (null != relativeBinding)
254 relativeBinding.Apply(true);
258 OnPropertyChanged(relativeProperty.PropertyName);
266 /// Sets the value of the specified property.
268 /// <param name="property">The BindableProperty on which to assign a value.</param>
269 /// <param name="value">The value to set.</param>
270 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
271 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
272 [EditorBrowsable(EditorBrowsableState.Never)]
273 public void SetValue(BindableProperty property, object value)
275 if (true == IsBinded)
277 SetValue(property, value, false, true);
281 if (null == property)
283 throw new ArgumentNullException(nameof(property));
286 object oldvalue = null;
287 if (null == property.DefaultValueCreator)
289 BindablePropertyContext context = GetOrCreateContext(property);
292 oldvalue = context.Value;
293 context.Value = value;
298 oldvalue = property.DefaultValueCreator.Invoke(this);
301 property.PropertyChanged?.Invoke(this, oldvalue, value);
303 OnPropertyChanged(property.PropertyName);
304 OnPropertyChangedWithData(property);
309 /// Sets the value of the propertyKey.
311 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
312 /// <param name="value">The value to set.</param>
313 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
314 [EditorBrowsable(EditorBrowsableState.Never)]
315 public void SetValue(BindablePropertyKey propertyKey, object value)
317 if (propertyKey == null)
318 throw new ArgumentNullException(nameof(propertyKey));
320 SetValue(propertyKey.BindableProperty, value, false, false);
324 /// Set the inherited context to a neated element.
326 /// <param name="bindable">The object on which to set the inherited binding context.</param>
327 /// <param name="value">The inherited context to set.</param>
328 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
329 [EditorBrowsable(EditorBrowsableState.Never)]
330 public static void SetInheritedBindingContext(BindableObject bindable, object value)
332 if (null == bindable)
334 throw new ArgumentNullException(nameof(bindable));
337 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
338 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
341 object oldContext = bindable.inheritedContext;
343 if (ReferenceEquals(oldContext, value))
346 if (bpContext != null && oldContext == null)
347 oldContext = bpContext.Value;
349 if (bpContext != null && bpContext.Binding != null)
351 bpContext.Binding.Context = value;
352 bindable.inheritedContext = null;
356 bindable.inheritedContext = value;
359 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
360 bindable.OnBindingContextChanged();
364 /// Register the properties which can effect each other in Binding to same group.
366 [EditorBrowsable(EditorBrowsableState.Never)]
367 public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
369 if (!PropertyToGroup.ContainsKey(property))
371 PropertyToGroup.Add(property, group);
374 if (null != group && !(group.Contains(property)))
380 /// Apply the bindings to BindingContext.
382 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
383 [EditorBrowsable(EditorBrowsableState.Never)]
384 protected void ApplyBindings()
386 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
390 /// Override this method to execute an action when the BindingContext changes.
392 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
393 [EditorBrowsable(EditorBrowsableState.Never)]
394 protected virtual void OnBindingContextChanged()
396 BindingContextChanged?.Invoke(this, EventArgs.Empty);
400 /// Call this method from a child class to notify that a change happened on a property.
402 /// <param name="propertyName">The name of the property that changed.</param>
403 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
404 [EditorBrowsable(EditorBrowsableState.Never)]
405 protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
406 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
409 /// Call this method from a child class to notify that a change is going to happen on a property.
411 /// <param name="propertyName">The name of the property that is changing.</param>
412 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
413 [EditorBrowsable(EditorBrowsableState.Never)]
414 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
415 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
418 /// Method that is called when a bound property is changed.
420 [EditorBrowsable(EditorBrowsableState.Never)]
421 protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
424 /// Unapplies all previously set bindings.
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 UnapplyBindings()
430 for (int i = 0, _propertiesCount = properties.Count; i < _propertiesCount; i++)
432 BindablePropertyContext context = properties[i];
433 if (context.Binding == null)
436 context.Binding.Unapply();
440 internal bool GetIsBound(BindableProperty targetProperty)
442 if (targetProperty == null)
443 throw new ArgumentNullException(nameof(targetProperty));
445 BindablePropertyContext bpcontext = GetContext(targetProperty);
446 return bpcontext != null && bpcontext.Binding != null;
450 /// Returns the value that is contained the BindableProperty.
452 /// <param name="property0">The BindableProperty instance.</param>
453 /// <param name="property1">The BindableProperty instance.</param>
454 /// <returns>The value that is contained the BindableProperty</returns>
455 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
457 var values = new object[2];
459 for (var i = 0; i < properties.Count; i++)
461 BindablePropertyContext context = properties[i];
463 if (ReferenceEquals(context.Property, property0))
465 values[0] = context.Value;
468 else if (ReferenceEquals(context.Property, property1))
470 values[1] = context.Value;
474 if (property0 == null && property1 == null)
478 if (!ReferenceEquals(property0, null))
479 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
480 if (!ReferenceEquals(property1, null))
481 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
487 /// Returns the value that is contained the BindableProperty.
489 /// <param name="property0">The BindableProperty instance.</param>
490 /// <param name="property1">The BindableProperty instance.</param>
491 /// <param name="property2">The BindableProperty instance.</param>
492 /// <returns>The value that is contained the BindableProperty</returns>
493 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
495 var values = new object[3];
497 for (var i = 0; i < properties.Count; i++)
499 BindablePropertyContext context = properties[i];
501 if (ReferenceEquals(context.Property, property0))
503 values[0] = context.Value;
506 else if (ReferenceEquals(context.Property, property1))
508 values[1] = context.Value;
511 else if (ReferenceEquals(context.Property, property2))
513 values[2] = context.Value;
517 if (property0 == null && property1 == null && property2 == null)
521 if (!ReferenceEquals(property0, null))
522 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
523 if (!ReferenceEquals(property1, null))
524 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
525 if (!ReferenceEquals(property2, null))
526 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
532 /// Returns the value that is contained the BindableProperty.
534 /// <param name="properties">The array of the BindableProperty instances</param>
535 /// <returns>The values that is contained the BindableProperty instances.</returns>
536 internal object[] GetValues(params BindableProperty[] properties)
538 var values = new object[properties.Length];
539 for (var i = 0; i < this.properties.Count; i++)
541 var context = this.properties[i];
542 var index = properties.IndexOf(context.Property);
545 values[index] = context.Value;
547 for (var i = 0; i < values.Length; i++)
549 if (!ReferenceEquals(values[i], null))
551 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
556 internal virtual void OnRemoveDynamicResource(BindableProperty property)
560 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
564 internal void RemoveDynamicResource(BindableProperty property)
566 if (property == null)
567 throw new ArgumentNullException(nameof(property));
569 OnRemoveDynamicResource(property);
570 BindablePropertyContext context = GetOrCreateContext(property);
571 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
574 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
576 if (targetProperty == null)
577 throw new ArgumentNullException(nameof(targetProperty));
579 throw new ArgumentNullException(nameof(binding));
581 if (fromStyle && !CanBeSetFromStyle(targetProperty))
586 var context = GetOrCreateContext(targetProperty);
588 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
590 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
592 if (context.Binding != null)
593 context.Binding.Unapply();
595 BindingBase oldBinding = context.Binding;
596 context.Binding = binding;
598 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
600 binding.Apply(BindingContext, this, targetProperty);
603 bool CanBeSetFromStyle(BindableProperty property)
605 var context = GetContext(property);
608 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
610 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
612 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
617 internal void SetDynamicResource(BindableProperty property, string key)
619 SetDynamicResource(property, key, false);
622 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
624 if (property == null)
625 throw new ArgumentNullException(nameof(property));
626 if (string.IsNullOrEmpty(key))
627 throw new ArgumentNullException(nameof(key));
628 if (fromStyle && !CanBeSetFromStyle(property))
631 var context = GetOrCreateContext(property);
633 context.Attributes |= BindableContextAttributes.IsDynamicResource;
635 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
637 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
639 OnSetDynamicResource(property, key);
642 internal void SetValue(BindableProperty property, object value, bool fromStyle)
644 SetValue(property, value, fromStyle, true);
647 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
649 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None);
653 /// For internal use.
655 /// <param name="property">The BindableProperty on which to assign a value.</param>
656 /// <param name="value">The value to set</param>
657 /// <param name="attributes">The set value flag</param>
658 [EditorBrowsable(EditorBrowsableState.Never)]
659 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
661 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default);
664 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
666 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
667 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
668 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
669 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
670 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
672 if (property == null)
673 throw new ArgumentNullException(nameof(property));
674 if (checkAccess && property.IsReadOnly)
676 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
680 if (!converted && !property.TryConvert(ref value))
682 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
686 if (property.ValidateValue != null && !property.ValidateValue(this, value))
687 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
689 if (property.CoerceValue != null)
690 value = property.CoerceValue(this, value);
692 BindablePropertyContext context = GetOrCreateContext(property);
695 context.Attributes |= BindableContextAttributes.IsManuallySet;
696 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
700 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
705 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
707 // else omitted on purpose
709 bool currentlyApplying = applying;
711 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
713 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
714 if (delayQueue == null)
715 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
717 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
721 context.Attributes |= BindableContextAttributes.IsBeingSet;
722 SetValueActual(property, context, value, currentlyApplying, attributes, silent);
724 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
725 if (delayQueue != null)
727 while (delayQueue.Count > 0)
729 SetValueArgs s = delayQueue.Dequeue();
730 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, s.Attributes);
733 context.DelayedSetters = null;
736 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
740 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
742 var prop = properties.ToArray();
743 for (int i = 0, propLength = prop.Length; i < propLength; i++)
745 BindablePropertyContext context = prop[i];
746 BindingBase binding = context.Binding;
750 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
753 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
754 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
758 internal bool IsBinded
764 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
766 bindable.inheritedContext = null;
767 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
768 bindable.OnBindingContextChanged();
770 if (newvalue is BindableObject targetBindableObject)
772 targetBindableObject.IsBinded = true;
776 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
778 object context = bindable.inheritedContext;
779 var oldBinding = oldBindingBase as Binding;
780 var newBinding = newBindingBase as Binding;
782 if (context == null && oldBinding != null)
783 context = oldBinding.Context;
784 if (context != null && newBinding != null)
785 newBinding.Context = context;
788 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
790 if (property == null)
791 throw new ArgumentNullException(nameof(property));
793 if (checkAccess && property.IsReadOnly)
794 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
796 BindablePropertyContext bpcontext = GetContext(property);
797 if (bpcontext == null)
800 if (fromStyle && !CanBeSetFromStyle(property))
803 object original = bpcontext.Value;
805 object newValue = property.GetDefaultValue(this);
807 bool same = Equals(original, newValue);
810 property.PropertyChanging?.Invoke(this, original, newValue);
812 OnPropertyChanging(property.PropertyName);
815 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
816 bpcontext.Value = newValue;
817 if (property.DefaultValueCreator == null)
818 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
820 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
824 OnPropertyChanged(property.PropertyName);
825 OnPropertyChangedWithData(property);
826 property.PropertyChanged?.Invoke(this, original, newValue);
830 [MethodImpl(MethodImplOptions.AggressiveInlining)]
831 BindablePropertyContext CreateAndAddContext(BindableProperty property)
833 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
835 if (property.DefaultValueCreator == null)
836 context.Attributes = BindableContextAttributes.IsDefaultValue;
838 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
840 properties.Add(context);
844 [MethodImpl(MethodImplOptions.AggressiveInlining)]
845 BindablePropertyContext GetContext(BindableProperty property)
847 List<BindablePropertyContext> propertyList = properties;
849 for (var i = 0; i < propertyList.Count; i++)
851 BindablePropertyContext context = propertyList[i];
852 if (ReferenceEquals(context.Property, property))
859 [MethodImpl(MethodImplOptions.AggressiveInlining)]
860 BindablePropertyContext GetOrCreateContext(BindableProperty property)
862 BindablePropertyContext context = GetContext(property);
865 context = CreateAndAddContext(property);
867 else if (property.DefaultValueCreator != null)
869 context.Value = property.DefaultValueCreator(this); //Update Value from dali
875 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
877 context.Binding.Unapply();
879 property.BindingChanging?.Invoke(this, context.Binding, null);
881 context.Binding = null;
884 internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
886 if (property == null)
887 throw new ArgumentNullException(nameof(property));
889 if (checkAccess && property.IsReadOnly)
890 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
892 if (fromStyle && !CanBeSetFromStyle(property))
895 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
896 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0));
899 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, bool silent = false)
901 object original = context.Value;
902 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
903 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
904 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
905 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
907 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
908 if (!silent && (!same || raiseOnEqual))
910 property.PropertyChanging?.Invoke(this, original, value);
912 OnPropertyChanging(property.PropertyName);
915 if (!same || raiseOnEqual)
917 context.Value = value;
920 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
921 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
923 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
924 RemoveDynamicResource(property);
926 BindingBase binding = context.Binding;
929 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
931 RemoveBinding(property, context);
936 PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
938 if (!silent && (!same || raiseOnEqual))
940 property.PropertyChanged?.Invoke(this, original, value);
942 if (binding != null && !currentlyApplying)
949 OnPropertyChanged(property.PropertyName);
951 if (null != propertyGroup)
953 foreach (var relativeProperty in propertyGroup)
955 if (relativeProperty != property)
957 var relativeContext = GetOrCreateContext(relativeProperty);
958 var relativeBinding = relativeContext.Binding;
960 if (null != relativeBinding)
963 relativeBinding.Apply(true);
967 OnPropertyChanged(relativeProperty.PropertyName);
972 OnPropertyChangedWithData(property);
976 private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
977 = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
980 enum BindableContextAttributes
982 IsManuallySet = 1 << 0,
984 IsDynamicResource = 1 << 2,
985 IsSetFromStyle = 1 << 3,
986 IsDefaultValue = 1 << 4,
987 IsDefaultValueCreated = 1 << 5,
990 class BindablePropertyContext
992 public BindableContextAttributes Attributes;
993 public BindingBase Binding;
994 public Queue<SetValueArgs> DelayedSetters;
995 public BindableProperty Property;
1000 internal enum SetValuePrivateFlags
1003 CheckAccess = 1 << 0,
1005 ManuallySet = 1 << 2,
1008 Default = CheckAccess
1013 public readonly SetValueFlags Attributes;
1014 public readonly BindablePropertyContext Context;
1015 public readonly bool CurrentlyApplying;
1016 public readonly BindableProperty Property;
1017 public readonly object Value;
1019 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
1021 Property = property;
1024 CurrentlyApplying = currentlyApplying;
1025 Attributes = attributes;
1031 namespace Tizen.NUI.Binding.Internals
1034 /// SetValueFlags. For internal use.
1037 [EditorBrowsable(EditorBrowsableState.Never)]
1038 public enum SetValueFlags
1043 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1044 [EditorBrowsable(EditorBrowsableState.Never)]
1048 /// Clear OneWay bindings.
1050 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1051 [EditorBrowsable(EditorBrowsableState.Never)]
1052 ClearOneWayBindings = 1 << 0,
1055 /// Clear TwoWay bindings.
1057 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1058 [EditorBrowsable(EditorBrowsableState.Never)]
1059 ClearTwoWayBindings = 1 << 1,
1062 /// Clear dynamic resource.
1064 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1065 [EditorBrowsable(EditorBrowsableState.Never)]
1066 ClearDynamicResource = 1 << 2,
1071 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
1072 [EditorBrowsable(EditorBrowsableState.Never)]
1073 RaiseOnEqual = 1 << 3