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, by enabling validation, type coercion, and an event system.
31 [EditorBrowsable(EditorBrowsableState.Never)]
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 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 public event PropertyChangedEventHandler PropertyChanged;
70 /// <summary>Copy properties of other ViewStyle to this.</summary>
71 /// <param name="other">The other BindableProperty merge to this.</param>
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 public virtual void CopyFrom(BindableObject other)
75 if (null == other) return;
77 Type type1 = this.GetType();
78 BindableProperty.GetBindablePropertysOfType(type1, out var nameToBindableProperty1);
80 Type type2 = other.GetType();
81 BindableProperty.GetBindablePropertysOfType(type2, out var nameToBindableProperty2);
83 if (null != nameToBindableProperty1)
85 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty1)
87 nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
89 if (null != bindableProperty)
91 object value = other.GetValue(bindableProperty);
95 SetValue(keyValuePair.Value, value);
103 /// Raised whenever the BindingContext property changes.
105 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
106 [EditorBrowsable(EditorBrowsableState.Never)]
107 public event EventHandler BindingContextChanged;
109 internal void ClearValue(BindableProperty property, bool fromStyle)
111 ClearValue(property, fromStyle: fromStyle, checkAccess: true);
115 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
117 /// <param name="property">The BindableProperty to clear</param>
118 internal void ClearValue(BindableProperty property)
120 ClearValue(property, fromStyle: false, checkAccess: true);
124 /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
126 /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
127 internal void ClearValue(BindablePropertyKey propertyKey)
129 if (propertyKey == null)
130 throw new ArgumentNullException(nameof(propertyKey));
132 ClearValue(propertyKey.BindableProperty, fromStyle: false, checkAccess: false);
136 /// Return true if the target property exists and has been set.
138 /// <param name="targetProperty">The target property</param>
139 /// <returns>return true if the target property exists and has been set</returns>
140 internal bool IsSet(BindableProperty targetProperty)
142 if (targetProperty == null)
143 throw new ArgumentNullException(nameof(targetProperty));
145 var bpcontext = GetContext(targetProperty);
146 return bpcontext != null
147 && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
151 /// Returns the value that is contained the BindableProperty.
153 /// <param name="property">The BindableProperty for which to get the value.</param>
154 /// <returns>The value that is contained the BindableProperty</returns>
155 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
156 [EditorBrowsable(EditorBrowsableState.Never)]
157 public object GetValue(BindableProperty property)
159 if (property == null)
160 throw new ArgumentNullException(nameof(property));
162 BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
165 return property.DefaultValue;
167 return context.Value;
171 /// Raised when a property is about to change.
173 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
174 [EditorBrowsable(EditorBrowsableState.Never)]
175 public event PropertyChangingEventHandler PropertyChanging;
178 /// Removes a previously set binding.
180 /// <param name="property">The BindableProperty from which to remove bindings.</param>
181 internal void RemoveBinding(BindableProperty property)
183 if (property == null)
184 throw new ArgumentNullException(nameof(property));
186 BindablePropertyContext context = GetContext(property);
187 if (context == null || context.Binding == null)
190 RemoveBinding(property, context);
194 /// Assigns a binding to a property.
196 /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
197 /// <param name="binding">The binding to set.</param>
198 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
199 [EditorBrowsable(EditorBrowsableState.Never)]
200 public void SetBinding(BindableProperty targetProperty, BindingBase binding)
202 SetBinding(targetProperty, binding, false);
205 private bool isCreateByXaml = false;
206 /// Only used by the IL of xaml, will never changed to not hidden.
207 [EditorBrowsable(EditorBrowsableState.Never)]
208 public virtual bool IsCreateByXaml
212 return isCreateByXaml;
216 isCreateByXaml = value;
221 /// Sets the value of the specified property.
223 /// <param name="property">The BindableProperty on which to assign a value.</param>
224 /// <param name="value">The value to set.</param>
225 /// <exception cref="ArgumentNullException"> Thrown when property is null. </exception>
226 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
227 [EditorBrowsable(EditorBrowsableState.Never)]
228 public void SetValue(BindableProperty property, object value)
230 if (true == isCreateByXaml)
232 SetValue(property, value, false, true);
236 if (null == property)
238 throw new ArgumentNullException(nameof(property));
240 property.PropertyChanged?.Invoke(this, null, value);
242 OnPropertyChanged(property.PropertyName);
243 OnPropertyChangedWithData(property);
247 internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
249 if (property == null)
250 throw new ArgumentNullException(nameof(property));
252 if (true == isCreateByXaml)
254 if (property.IsReadOnly)
255 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
257 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
258 SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
262 property.PropertyChanged?.Invoke(this, null, value);
267 /// Sets the value of the propertyKey.
269 /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
270 /// <param name="value">The value to set.</param>
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(BindablePropertyKey propertyKey, object value)
275 if (propertyKey == null)
276 throw new ArgumentNullException(nameof(propertyKey));
278 SetValue(propertyKey.BindableProperty, value, false, false);
282 /// Set the inherited context to a neated element.
284 /// <param name="bindable">The object on which to set the inherited binding context.</param>
285 /// <param name="value">The inherited context to set.</param>
286 /// <exception cref="ArgumentNullException"> Thrown when bindable is null. </exception>
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 public static void SetInheritedBindingContext(BindableObject bindable, object value)
290 if (null == bindable)
292 throw new ArgumentNullException(nameof(bindable));
295 BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
296 if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
299 object oldContext = bindable.inheritedContext;
301 if (ReferenceEquals(oldContext, value))
304 if (bpContext != null && oldContext == null)
305 oldContext = bpContext.Value;
307 if (bpContext != null && bpContext.Binding != null)
309 bpContext.Binding.Context = value;
310 bindable.inheritedContext = null;
314 bindable.inheritedContext = value;
317 bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
318 bindable.OnBindingContextChanged();
322 /// Apply the bindings to BindingContext.
324 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
325 [EditorBrowsable(EditorBrowsableState.Never)]
326 protected void ApplyBindings()
328 ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
332 /// Override this method to execute an action when the BindingContext changes.
334 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
335 [EditorBrowsable(EditorBrowsableState.Never)]
336 protected virtual void OnBindingContextChanged()
338 BindingContextChanged?.Invoke(this, EventArgs.Empty);
342 /// Call this method from a child class to notify that a change happened on a property.
344 /// <param name="propertyName">The name of the property that changed.</param>
345 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
346 [EditorBrowsable(EditorBrowsableState.Never)]
347 protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
348 => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
351 /// Call this method from a child class to notify that a change is going to happen on a property.
353 /// <param name="propertyName">The name of the property that is changing.</param>
354 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
355 [EditorBrowsable(EditorBrowsableState.Never)]
356 protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
357 => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
360 /// Method that is called when a bound property is changed.
362 [EditorBrowsable(EditorBrowsableState.Never)]
363 protected virtual void OnPropertyChangedWithData(BindableProperty property) { }
366 /// Unapplies all previously set bindings.
368 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
369 [EditorBrowsable(EditorBrowsableState.Never)]
370 protected void UnapplyBindings()
372 for (int i = 0, _propertiesCount = properties.Count; i < _propertiesCount; i++)
374 BindablePropertyContext context = properties[i];
375 if (context.Binding == null)
378 context.Binding.Unapply();
382 internal bool GetIsBound(BindableProperty targetProperty)
384 if (targetProperty == null)
385 throw new ArgumentNullException(nameof(targetProperty));
387 BindablePropertyContext bpcontext = GetContext(targetProperty);
388 return bpcontext != null && bpcontext.Binding != null;
392 /// Returns the value that is contained the BindableProperty.
394 /// <param name="property0">The BindableProperty instance.</param>
395 /// <param name="property1">The BindableProperty instance.</param>
396 /// <returns>The value that is contained the BindableProperty</returns>
397 internal object[] GetValues(BindableProperty property0, BindableProperty property1)
399 var values = new object[2];
401 for (var i = 0; i < properties.Count; i++)
403 BindablePropertyContext context = properties[i];
405 if (ReferenceEquals(context.Property, property0))
407 values[0] = context.Value;
410 else if (ReferenceEquals(context.Property, property1))
412 values[1] = context.Value;
416 if (property0 == null && property1 == null)
420 if (!ReferenceEquals(property0, null))
421 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
422 if (!ReferenceEquals(property1, null))
423 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
429 /// Returns the value that is contained the BindableProperty.
431 /// <param name="property0">The BindableProperty instance.</param>
432 /// <param name="property1">The BindableProperty instance.</param>
433 /// <param name="property2">The BindableProperty instance.</param>
434 /// <returns>The value that is contained the BindableProperty</returns>
435 internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
437 var values = new object[3];
439 for (var i = 0; i < properties.Count; i++)
441 BindablePropertyContext context = properties[i];
443 if (ReferenceEquals(context.Property, property0))
445 values[0] = context.Value;
448 else if (ReferenceEquals(context.Property, property1))
450 values[1] = context.Value;
453 else if (ReferenceEquals(context.Property, property2))
455 values[2] = context.Value;
459 if (property0 == null && property1 == null && property2 == null)
463 if (!ReferenceEquals(property0, null))
464 values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
465 if (!ReferenceEquals(property1, null))
466 values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
467 if (!ReferenceEquals(property2, null))
468 values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
474 /// Returns the value that is contained the BindableProperty.
476 /// <param name="properties">The array of the BindableProperty instances</param>
477 /// <returns>The values that is contained the BindableProperty instances.</returns>
478 internal object[] GetValues(params BindableProperty[] properties)
480 var values = new object[properties.Length];
481 for (var i = 0; i < this.properties.Count; i++)
483 var context = this.properties[i];
484 var index = properties.IndexOf(context.Property);
487 values[index] = context.Value;
489 for (var i = 0; i < values.Length; i++)
491 if (!ReferenceEquals(values[i], null))
493 values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
498 internal virtual void OnRemoveDynamicResource(BindableProperty property)
502 internal virtual void OnSetDynamicResource(BindableProperty property, string key)
506 internal void RemoveDynamicResource(BindableProperty property)
508 if (property == null)
509 throw new ArgumentNullException(nameof(property));
511 OnRemoveDynamicResource(property);
512 BindablePropertyContext context = GetOrCreateContext(property);
513 context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
516 internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
518 if (targetProperty == null)
519 throw new ArgumentNullException(nameof(targetProperty));
521 throw new ArgumentNullException(nameof(binding));
523 if (fromStyle && !CanBeSetFromStyle(targetProperty))
526 var context = GetOrCreateContext(targetProperty);
528 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
530 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
532 if (context.Binding != null)
533 context.Binding.Unapply();
535 BindingBase oldBinding = context.Binding;
536 context.Binding = binding;
538 targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
540 binding.Apply(BindingContext, this, targetProperty);
543 bool CanBeSetFromStyle(BindableProperty property)
545 var context = GetContext(property);
548 if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
550 if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
552 if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
557 internal void SetDynamicResource(BindableProperty property, string key)
559 SetDynamicResource(property, key, false);
562 internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
564 if (property == null)
565 throw new ArgumentNullException(nameof(property));
566 if (string.IsNullOrEmpty(key))
567 throw new ArgumentNullException(nameof(key));
568 if (fromStyle && !CanBeSetFromStyle(property))
571 var context = GetOrCreateContext(property);
573 context.Attributes |= BindableContextAttributes.IsDynamicResource;
575 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
577 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
579 OnSetDynamicResource(property, key);
582 internal void SetValue(BindableProperty property, object value, bool fromStyle)
584 SetValue(property, value, fromStyle, true);
587 internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
589 SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
593 /// For internal use.
595 /// <param name="property">The BindableProperty on which to assign a value.</param>
596 /// <param name="value">The value to set</param>
597 /// <param name="attributes">The set value flag</param>
598 [EditorBrowsable(EditorBrowsableState.Never)]
599 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
601 SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
604 internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
606 bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
607 bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
608 bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
609 bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
610 bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
612 if (property == null)
613 throw new ArgumentNullException(nameof(property));
614 if (checkAccess && property.IsReadOnly)
616 Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
620 if (!converted && !property.TryConvert(ref value))
622 Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
626 if (property.ValidateValue != null && !property.ValidateValue(this, value))
627 throw new ArgumentException("Value was an invalid value for " + property.PropertyName, nameof(value));
629 if (property.CoerceValue != null)
630 value = property.CoerceValue(this, value);
632 BindablePropertyContext context = GetOrCreateContext(property);
635 context.Attributes |= BindableContextAttributes.IsManuallySet;
636 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
639 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
642 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
643 // else omitted on purpose
645 bool currentlyApplying = applying;
647 if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
649 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
650 if (delayQueue == null)
651 context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
653 delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
657 context.Attributes |= BindableContextAttributes.IsBeingSet;
658 SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
660 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
661 if (delayQueue != null)
663 while (delayQueue.Count > 0)
665 SetValueArgs s = delayQueue.Dequeue();
666 SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
669 context.DelayedSetters = null;
672 context.Attributes &= ~BindableContextAttributes.IsBeingSet;
676 internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
678 var prop = properties.ToArray();
679 for (int i = 0, propLength = prop.Length; i < propLength; i++)
681 BindablePropertyContext context = prop[i];
682 BindingBase binding = context.Binding;
686 if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
689 binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
690 binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
694 static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
696 object context = bindable.inheritedContext;
697 var oldBinding = oldBindingBase as Binding;
698 var newBinding = newBindingBase as Binding;
700 if (context == null && oldBinding != null)
701 context = oldBinding.Context;
702 if (context != null && newBinding != null)
703 newBinding.Context = context;
706 static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
708 bindable.inheritedContext = null;
709 bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
710 bindable.OnBindingContextChanged();
713 void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
715 if (property == null)
716 throw new ArgumentNullException(nameof(property));
718 if (checkAccess && property.IsReadOnly)
719 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
721 BindablePropertyContext bpcontext = GetContext(property);
722 if (bpcontext == null)
725 if (fromStyle && !CanBeSetFromStyle(property))
728 object original = bpcontext.Value;
730 object newValue = property.GetDefaultValue(this);
732 bool same = Equals(original, newValue);
735 property.PropertyChanging?.Invoke(this, original, newValue);
737 OnPropertyChanging(property.PropertyName);
740 bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
741 bpcontext.Value = newValue;
742 if (property.DefaultValueCreator == null)
743 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
745 bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
749 OnPropertyChanged(property.PropertyName);
750 OnPropertyChangedWithData(property);
751 property.PropertyChanged?.Invoke(this, original, newValue);
755 [MethodImpl(MethodImplOptions.AggressiveInlining)]
756 BindablePropertyContext CreateAndAddContext(BindableProperty property)
758 var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
760 if (property.DefaultValueCreator == null)
761 context.Attributes = BindableContextAttributes.IsDefaultValue;
763 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
765 properties.Add(context);
769 [MethodImpl(MethodImplOptions.AggressiveInlining)]
770 BindablePropertyContext GetContext(BindableProperty property)
772 List<BindablePropertyContext> propertyList = properties;
774 for (var i = 0; i < propertyList.Count; i++)
776 BindablePropertyContext context = propertyList[i];
777 if (ReferenceEquals(context.Property, property))
784 [MethodImpl(MethodImplOptions.AggressiveInlining)]
785 BindablePropertyContext GetOrCreateContext(BindableProperty property)
787 BindablePropertyContext context = GetContext(property);
790 context = CreateAndAddContext(property);
792 else if (property.DefaultValueCreator != null)
794 context.Value = property.DefaultValueCreator(this); //Update Value from dali
800 void RemoveBinding(BindableProperty property, BindablePropertyContext context)
802 context.Binding.Unapply();
804 property.BindingChanging?.Invoke(this, context.Binding, null);
806 context.Binding = null;
809 void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
811 if (property == null)
812 throw new ArgumentNullException(nameof(property));
814 if (checkAccess && property.IsReadOnly)
815 throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
817 if (fromStyle && !CanBeSetFromStyle(property))
820 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
821 (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
825 void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
827 object original = context.Value;
828 bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
829 bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
830 bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
831 bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
833 bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
834 if (!silent && (!same || raiseOnEqual))
836 property.PropertyChanging?.Invoke(this, original, value);
838 OnPropertyChanging(property.PropertyName);
841 if (!same || raiseOnEqual)
843 context.Value = value;
846 context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
847 context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
849 if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
850 RemoveDynamicResource(property);
852 BindingBase binding = context.Binding;
855 if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
857 RemoveBinding(property, context);
864 if ((!same || raiseOnEqual))
866 property.PropertyChanged?.Invoke(this, original, value);
868 if (binding != null && !currentlyApplying)
875 OnPropertyChanged(property.PropertyName);
877 else if (true == same && true == forceSendChangeSignal)
879 if (binding != null && !currentlyApplying)
886 OnPropertyChanged(property.PropertyName);
889 OnPropertyChangedWithData(property);
894 enum BindableContextAttributes
896 IsManuallySet = 1 << 0,
898 IsDynamicResource = 1 << 2,
899 IsSetFromStyle = 1 << 3,
900 IsDefaultValue = 1 << 4,
901 IsDefaultValueCreated = 1 << 5,
904 class BindablePropertyContext
906 public BindableContextAttributes Attributes;
907 public BindingBase Binding;
908 public Queue<SetValueArgs> DelayedSetters;
909 public BindableProperty Property;
914 internal enum SetValuePrivateFlags
917 CheckAccess = 1 << 0,
919 ManuallySet = 1 << 2,
922 Default = CheckAccess
927 public readonly SetValueFlags Attributes;
928 public readonly BindablePropertyContext Context;
929 public readonly bool CurrentlyApplying;
930 public readonly BindableProperty Property;
931 public readonly object Value;
933 public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
938 CurrentlyApplying = currentlyApplying;
939 Attributes = attributes;
945 namespace Tizen.NUI.Binding.Internals
948 /// SetValueFlags. For internal use.
951 [EditorBrowsable(EditorBrowsableState.Never)]
952 public enum SetValueFlags
957 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
958 [EditorBrowsable(EditorBrowsableState.Never)]
962 /// Clear OneWay bindings.
964 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
965 [EditorBrowsable(EditorBrowsableState.Never)]
966 ClearOneWayBindings = 1 << 0,
969 /// Clear TwoWay bindings.
971 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
972 [EditorBrowsable(EditorBrowsableState.Never)]
973 ClearTwoWayBindings = 1 << 1,
976 /// Clear dynamic resource.
978 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
979 [EditorBrowsable(EditorBrowsableState.Never)]
980 ClearDynamicResource = 1 << 2,
985 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
986 [EditorBrowsable(EditorBrowsableState.Never)]
987 RaiseOnEqual = 1 << 3