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;
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),
40 BindingMode.OneWay, null, BindingContextPropertyChanged, null, null, BindingContextPropertyBindingChanging);
42 readonly List<BindablePropertyContext> properties = new List<BindablePropertyContext>(4);
45 object inheritedContext;
48 /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
50 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
51 [EditorBrowsable(EditorBrowsableState.Never)]
52 public object BindingContext
54 get { return inheritedContext ?? GetValue(BindingContextProperty); }
55 set { SetValue(BindingContextProperty, value); }
58 void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
60 SetDynamicResource(property, key, false);
64 /// Raised when a property has changed.
66 /// <since_tizen> 9 </since_tizen>
67 public event PropertyChangedEventHandler PropertyChanged;
69 /// <summary>Copy properties of other ViewStyle to this.</summary>
70 /// <param name="other">The other BindableProperty merge to this.</param>
71 [EditorBrowsable(EditorBrowsableState.Never)]
72 public virtual void CopyFrom(BindableObject other)
74 if (null == other) return;
76 Type type1 = this.GetType();
77 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
79 Type type2 = other.GetType();
80 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
82 if (null != nameToBindableProperty1)
84 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
86 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
88 if (null != bindableProperty)
90 object value = other.GetValue(bindableProperty);
94 SetValue(keyValuePair.Value, value);
102 /// Raised whenever the BindingContext property changes.
104 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
105 [EditorBrowsable(EditorBrowsableState.Never)]
106 public event EventHandler BindingContextChanged;
108 internal void ClearValue(BindableProperty property, bool fromStyle)
110 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
114 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
116 /// <param name="property">The BindableProperty to clear</param>
117 internal void ClearValue(BindableProperty property)
119 ClearValue(property, fromStyle: false, checkAccess: true);
123 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
125 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
126 internal void ClearValue(BindablePropertyKey propertyKey)
128 if (propertyKey == null)
129 throw new ArgumentNullException(nameof(propertyKey));
131 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
135 /// Return true if the target property exists and has been set.
137 /// <param name="targetProperty">The target property</param>
138 /// <returns>return true if the target property exists and has been set</returns>
139 internal bool IsSet(BindableProperty targetProperty)
141 if (targetProperty == null)
142 throw new ArgumentNullException(nameof(targetProperty));
144 var bpcontext = GetContext(targetProperty);
145 return bpcontext != null
146 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
150 /// Returns the value that is contained the BindableProperty.
152 /// <param name="property">The BindableProperty for which to get the value.</param>
153 /// <returns>The value that is contained the BindableProperty</returns>
154 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
155 [EditorBrowsable(EditorBrowsableState.Never)]
156 public object GetValue(BindableProperty property)
158 if (property == null)
159 throw new ArgumentNullException(nameof(property));
161 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
164 return property.DefaultValue;
166 return context.Value;
170 /// Raised when a property is about to change.
172 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
173 [EditorBrowsable(EditorBrowsableState.Never)]
174 public event PropertyChangingEventHandler PropertyChanging;
177 /// Removes a previously set binding.
179 /// <param name="property">The BindableProperty from which to remove bindings.</param>
180 internal void RemoveBinding(BindableProperty property)
182 if (property == null)
183 throw new ArgumentNullException(nameof(property));
185 BindablePropertyContext context = GetContext(property);
186 if (context == null || context.Binding == null)
189 RemoveBinding(property, context);
193 /// Assigns a binding to a property.
195 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
196 /// <param name="binding">The binding to set.</param>
197 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
198 [EditorBrowsable(EditorBrowsableState.Never)]
199 public void SetBinding(BindableProperty targetProperty, BindingBase binding)
201 SetBinding(targetProperty, binding, false);
204 private bool isCreateByXaml = false;
205 /// Only used by the IL of xaml, will never changed to not hidden.
206 [EditorBrowsable(EditorBrowsableState.Never)]
207 public virtual bool IsCreateByXaml
211 return isCreateByXaml;
215 isCreateByXaml = value;
220 /// Sets the value of the specified property.
222 /// <param name="property">The BindableProperty on which to assign a value.</param>
223 /// <param name="value">The value to set.</param>
224 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
225 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
226 [EditorBrowsable(EditorBrowsableState.Never)]
227 public void SetValue(BindableProperty property, object value)
229 if (true == isCreateByXaml)
231 SetValue(property, value, false, true);
235 if (null == property)
237 throw new ArgumentNullException(nameof(property));
239 property.PropertyChanged?.Invoke(this, null, value);
241 OnPropertyChanged(property.PropertyName);
242 OnPropertyChangedWithData(property);
246 internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
248 if (property == null)
249 throw new ArgumentNullException(nameof(property));
251 if (true == isCreateByXaml)
253 if (property.IsReadOnly)
254 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
256 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
257 SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
261 property.PropertyChanged?.Invoke(this, null, value);
266 /// Sets the value of the propertyKey.
268 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
269 /// <param name="value">The value to set.</param>
270 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
271 [EditorBrowsable(EditorBrowsableState.Never)]
272 public void SetValue(BindablePropertyKey propertyKey, object value)
274 if (propertyKey == null)
275 throw new ArgumentNullException(nameof(propertyKey));
277 SetValue(propertyKey.BindableProperty, value, false, false);
281 /// Set the inherited context to a neated element.
283 /// <param name="bindable">The object on which to set the inherited binding context.</param>
284 /// <param name="value">The inherited context to set.</param>
285 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
286 [EditorBrowsable(EditorBrowsableState.Never)]
287 public static void SetInheritedBindingContext(BindableObject bindable, object value)
289 if (null == bindable)
291 throw new ArgumentNullException(nameof(bindable));
294 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
295 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
298 object oldContext = bindable.inheritedContext;
300 if (ReferenceEquals(oldContext, value))
303 if (bpContext != null && oldContext == null)
304 oldContext = bpContext.Value;
306 if (bpContext != null && bpContext.Binding != null)
308 bpContext.Binding.Context = value;
309 bindable.inheritedContext = null;
313 bindable.inheritedContext = value;
316 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
317 bindable.OnBindingContextChanged();
321 /// Apply the bindings to BindingContext.
323 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
324 [EditorBrowsable(EditorBrowsableState.Never)]
325 protected void ApplyBindings()
327 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
331 /// Override this method to execute an action when the BindingContext changes.
333 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
334 [EditorBrowsable(EditorBrowsableState.Never)]
335 protected virtual void OnBindingContextChanged()
337 BindingContextChanged?.Invoke(this, EventArgs.Empty);
341 /// Call this method from a child class to notify that a change happened on a property.
343 /// <param name="propertyName">The name of the property that changed.</param>
344 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
345 [EditorBrowsable(EditorBrowsableState.Never)]
346 protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
347 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
350 /// Call this method from a child class to notify that a change is going to happen on a property.
352 /// <param name="propertyName">The name of the property that is changing.</param>
353 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
354 [EditorBrowsable(EditorBrowsableState.Never)]
355 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
356 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
359 /// Method that is called when a bound property is changed.
361 [EditorBrowsable(EditorBrowsableState.Never)]
362 protected virtual void OnPropertyChangedWithData(BindableProperty property) { }
365 /// Unapplies all previously set bindings.
367 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
368 [EditorBrowsable(EditorBrowsableState.Never)]
369 protected void UnapplyBindings()
371 for (int i = 0, _propertiesCount = properties.Count; i < _propertiesCount; i++)
373 BindablePropertyContext context = properties[i];
374 if (context.Binding == null)
377 context.Binding.Unapply();
381 internal bool GetIsBound(BindableProperty targetProperty)
383 if (targetProperty == null)
384 throw new ArgumentNullException(nameof(targetProperty));
386 BindablePropertyContext bpcontext = GetContext(targetProperty);
387 return bpcontext != null && bpcontext.Binding != null;
391 /// Returns the value that is contained the BindableProperty.
393 /// <param name="property0">The BindableProperty instance.</param>
394 /// <param name="property1">The BindableProperty instance.</param>
395 /// <returns>The value that is contained the BindableProperty</returns>
396 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
398 var values = new object[2];
400 for (var i = 0; i < properties.Count; i++)
402 BindablePropertyContext context = properties[i];
404 if (ReferenceEquals(context.Property, property0))
406 values[0] = context.Value;
409 else if (ReferenceEquals(context.Property, property1))
411 values[1] = context.Value;
415 if (property0 == null && property1 == null)
419 if (!ReferenceEquals(property0, null))
420 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
421 if (!ReferenceEquals(property1, null))
422 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
428 /// Returns the value that is contained the BindableProperty.
430 /// <param name="property0">The BindableProperty instance.</param>
431 /// <param name="property1">The BindableProperty instance.</param>
432 /// <param name="property2">The BindableProperty instance.</param>
433 /// <returns>The value that is contained the BindableProperty</returns>
434 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
436 var values = new object[3];
438 for (var i = 0; i < properties.Count; i++)
440 BindablePropertyContext context = properties[i];
442 if (ReferenceEquals(context.Property, property0))
444 values[0] = context.Value;
447 else if (ReferenceEquals(context.Property, property1))
449 values[1] = context.Value;
452 else if (ReferenceEquals(context.Property, property2))
454 values[2] = context.Value;
458 if (property0 == null && property1 == null && property2 == null)
462 if (!ReferenceEquals(property0, null))
463 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
464 if (!ReferenceEquals(property1, null))
465 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
466 if (!ReferenceEquals(property2, null))
467 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
473 /// Returns the value that is contained the BindableProperty.
475 /// <param name="properties">The array of the BindableProperty instances</param>
476 /// <returns>The values that is contained the BindableProperty instances.</returns>
477 internal object[] GetValues(params BindableProperty[] properties)
479 var values = new object[properties.Length];
480 for (var i = 0; i < this.properties.Count; i++)
482 var context = this.properties[i];
483 var index = properties.IndexOf(context.Property);
486 values[index] = context.Value;
488 for (var i = 0; i < values.Length; i++)
490 if (!ReferenceEquals(values[i], null))
492 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
497 internal virtual void OnRemoveDynamicResource(BindableProperty property)
501 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
505 internal void RemoveDynamicResource(BindableProperty property)
507 if (property == null)
508 throw new ArgumentNullException(nameof(property));
510 OnRemoveDynamicResource(property);
511 BindablePropertyContext context = GetOrCreateContext(property);
512 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
515 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
517 if (targetProperty == null)
518 throw new ArgumentNullException(nameof(targetProperty));
520 throw new ArgumentNullException(nameof(binding));
522 if (fromStyle && !CanBeSetFromStyle(targetProperty))
525 IsCreateByXaml = true;
527 var context = GetOrCreateContext(targetProperty);
529 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
531 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
533 if (context.Binding != null)
534 context.Binding.Unapply();
536 BindingBase oldBinding = context.Binding;
537 context.Binding = binding;
539 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
541 binding.Apply(BindingContext, this, targetProperty);
544 bool CanBeSetFromStyle(BindableProperty property)
546 var context = GetContext(property);
549 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
551 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
553 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
558 internal void SetDynamicResource(BindableProperty property, string key)
560 SetDynamicResource(property, key, false);
563 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
565 if (property == null)
566 throw new ArgumentNullException(nameof(property));
567 if (string.IsNullOrEmpty(key))
568 throw new ArgumentNullException(nameof(key));
569 if (fromStyle && !CanBeSetFromStyle(property))
572 var context = GetOrCreateContext(property);
574 context.Attributes |= BindableContextAttributes.IsDynamicResource;
576 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
578 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
580 OnSetDynamicResource(property, key);
583 internal void SetValue(BindableProperty property, object value, bool fromStyle)
585 SetValue(property, value, fromStyle, true);
588 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
590 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
594 /// For internal use.
596 /// <param name="property">The BindableProperty on which to assign a value.</param>
597 /// <param name="value">The value to set</param>
598 /// <param name="attributes">The set value flag</param>
599 [EditorBrowsable(EditorBrowsableState.Never)]
600 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
602 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
605 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
607 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
608 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
609 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
610 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
611 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
613 if (property == null)
614 throw new ArgumentNullException(nameof(property));
615 if (checkAccess && property.IsReadOnly)
617 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
621 if (!converted && !property.TryConvert(ref value))
623 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
627 if (property.ValidateValue != null && !property.ValidateValue(this, value))
628 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
630 if (property.CoerceValue != null)
631 value = property.CoerceValue(this, value);
633 BindablePropertyContext context = GetOrCreateContext(property);
636 context.Attributes |= BindableContextAttributes.IsManuallySet;
637 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
640 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
643 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
644 // else omitted on purpose
646 bool currentlyApplying = applying;
648 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
650 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
651 if (delayQueue == null)
652 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
654 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
658 context.Attributes |= BindableContextAttributes.IsBeingSet;
659 SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
661 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
662 if (delayQueue != null)
664 while (delayQueue.Count > 0)
666 SetValueArgs s = delayQueue.Dequeue();
667 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
670 context.DelayedSetters = null;
673 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
677 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
679 var prop = properties.ToArray();
680 for (int i = 0, propLength = prop.Length; i < propLength; i++)
682 BindablePropertyContext context = prop[i];
683 BindingBase binding = context.Binding;
687 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
690 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
691 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
695 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
697 object context = bindable.inheritedContext;
698 var oldBinding = oldBindingBase as Binding;
699 var newBinding = newBindingBase as Binding;
701 if (context == null && oldBinding != null)
702 context = oldBinding.Context;
703 if (context != null && newBinding != null)
704 newBinding.Context = context;
707 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
709 bindable.inheritedContext = null;
710 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
711 bindable.OnBindingContextChanged();
714 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
716 if (property == null)
717 throw new ArgumentNullException(nameof(property));
719 if (checkAccess && property.IsReadOnly)
720 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
722 BindablePropertyContext bpcontext = GetContext(property);
723 if (bpcontext == null)
726 if (fromStyle && !CanBeSetFromStyle(property))
729 object original = bpcontext.Value;
731 object newValue = property.GetDefaultValue(this);
733 bool same = Equals(original, newValue);
736 property.PropertyChanging?.Invoke(this, original, newValue);
738 OnPropertyChanging(property.PropertyName);
741 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
742 bpcontext.Value = newValue;
743 if (property.DefaultValueCreator == null)
744 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
746 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
750 OnPropertyChanged(property.PropertyName);
751 OnPropertyChangedWithData(property);
752 property.PropertyChanged?.Invoke(this, original, newValue);
756 [MethodImpl(MethodImplOptions.AggressiveInlining)]
757 BindablePropertyContext CreateAndAddContext(BindableProperty property)
759 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
761 if (property.DefaultValueCreator == null)
762 context.Attributes = BindableContextAttributes.IsDefaultValue;
764 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
766 properties.Add(context);
770 [MethodImpl(MethodImplOptions.AggressiveInlining)]
771 BindablePropertyContext GetContext(BindableProperty property)
773 List<BindablePropertyContext> propertyList = properties;
775 for (var i = 0; i < propertyList.Count; i++)
777 BindablePropertyContext context = propertyList[i];
778 if (ReferenceEquals(context.Property, property))
785 [MethodImpl(MethodImplOptions.AggressiveInlining)]
786 BindablePropertyContext GetOrCreateContext(BindableProperty property)
788 BindablePropertyContext context = GetContext(property);
791 context = CreateAndAddContext(property);
793 else if (property.DefaultValueCreator != null)
795 context.Value = property.DefaultValueCreator(this); //Update Value from dali
801 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
803 context.Binding.Unapply();
805 property.BindingChanging?.Invoke(this, context.Binding, null);
807 context.Binding = null;
810 void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
812 if (property == null)
813 throw new ArgumentNullException(nameof(property));
815 if (checkAccess && property.IsReadOnly)
816 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
818 if (fromStyle && !CanBeSetFromStyle(property))
821 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
822 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
826 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
828 object original = context.Value;
829 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
830 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
831 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
832 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
834 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
835 if (!silent && (!same || raiseOnEqual))
837 property.PropertyChanging?.Invoke(this, original, value);
839 OnPropertyChanging(property.PropertyName);
842 if (!same || raiseOnEqual)
844 context.Value = value;
847 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
848 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
850 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
851 RemoveDynamicResource(property);
853 BindingBase binding = context.Binding;
856 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
858 RemoveBinding(property, context);
865 if ((!same || raiseOnEqual))
867 property.PropertyChanged?.Invoke(this, original, value);
869 if (binding != null && !currentlyApplying)
876 OnPropertyChanged(property.PropertyName);
878 else if (true == same && true == forceSendChangeSignal)
880 if (binding != null && !currentlyApplying)
887 OnPropertyChanged(property.PropertyName);
890 OnPropertyChangedWithData(property);
895 enum BindableContextAttributes
897 IsManuallySet = 1 << 0,
899 IsDynamicResource = 1 << 2,
900 IsSetFromStyle = 1 << 3,
901 IsDefaultValue = 1 << 4,
902 IsDefaultValueCreated = 1 << 5,
905 class BindablePropertyContext
907 public BindableContextAttributes Attributes;
908 public BindingBase Binding;
909 public Queue<SetValueArgs> DelayedSetters;
910 public BindableProperty Property;
915 internal enum SetValuePrivateFlags
918 CheckAccess = 1 << 0,
920 ManuallySet = 1 << 2,
923 Default = CheckAccess
928 public readonly SetValueFlags Attributes;
929 public readonly BindablePropertyContext Context;
930 public readonly bool CurrentlyApplying;
931 public readonly BindableProperty Property;
932 public readonly object Value;
934 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
939 CurrentlyApplying = currentlyApplying;
940 Attributes = attributes;
946 namespace Tizen.NUI.Binding.Internals
949 /// SetValueFlags. For internal use.
952 [EditorBrowsable(EditorBrowsableState.Never)]
953 public enum SetValueFlags
958 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
959 [EditorBrowsable(EditorBrowsableState.Never)]
963 /// Clear OneWay bindings.
965 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
966 [EditorBrowsable(EditorBrowsableState.Never)]
967 ClearOneWayBindings = 1 << 0,
970 /// Clear TwoWay bindings.
972 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
973 [EditorBrowsable(EditorBrowsableState.Never)]
974 ClearTwoWayBindings = 1 << 1,
977 /// Clear dynamic resource.
979 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
980 [EditorBrowsable(EditorBrowsableState.Never)]
981 ClearDynamicResource = 1 << 2,
986 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
987 [EditorBrowsable(EditorBrowsableState.Never)]
988 RaiseOnEqual = 1 << 3