[NUI] Public RemoveBinding and ClearBinding apis
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / BindableObject.cs
index 4e33927..b5390fa 100755 (executable)
@@ -1,17 +1,35 @@
-using System;
+/*
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Diagnostics;
 using System.Reflection;
+using System.Linq;
 using System.Runtime.CompilerServices;
 using Tizen.NUI.Binding.Internals;
 
 namespace Tizen.NUI.Binding
 {
     /// <summary>
-    /// 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.
+    /// Provides a mechanism by which application developers can propagate changes that are made to data in one object to another.
     /// </summary>
-    [EditorBrowsable(EditorBrowsableState.Never)]
+    /// <since_tizen> 9 </since_tizen>
     public abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
     {
         /// <summary>
@@ -19,13 +37,13 @@ namespace Tizen.NUI.Binding
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public static readonly BindableProperty BindingContextProperty =
-            BindableProperty.Create(nameof(BindingContext), typeof(object), typeof(BindableObject), default(object),
-                                    BindingMode.OneWay, null, BindingContextPropertyChanged, null, null, BindingContextPropertyBindingChanging);
+            BindableProperty.Create(nameof(BindingContext), typeof(object), typeof(BindableObject),  default(object), BindingMode.OneWay, null, BindingContextPropertyChanged,
+            null, null, BindingContextPropertyBindingChanging);
 
-        readonly List<BindablePropertyContext> _properties = new List<BindablePropertyContext>(4);
+        readonly Dictionary<BindableProperty, BindablePropertyContext> properties = new Dictionary<BindableProperty, BindablePropertyContext>(4);
 
-        bool _applying;
-        object _inheritedContext;
+        bool applying;
+        object inheritedContext;
 
         /// <summary>
         /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
@@ -34,26 +52,24 @@ namespace Tizen.NUI.Binding
         [EditorBrowsable(EditorBrowsableState.Never)]
         public object BindingContext
         {
-            get { return _inheritedContext ?? GetValue(BindingContextProperty); }
+            get { return inheritedContext ?? GetValue(BindingContextProperty); }
             set { SetValue(BindingContextProperty, value); }
         }
 
-        void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
-        {
-            SetDynamicResource(property, key, false);
-        }
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int LineNumber { get; set; } = -1;
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int LinePosition { get; set; } = -1;
+
+        void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key) => SetDynamicResource(property, key, false);
 
         /// <summary>
         /// Raised when a property has changed.
         /// </summary>
-        /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
-        [EditorBrowsable(EditorBrowsableState.Never)]
+        /// <since_tizen> 9 </since_tizen>
         public event PropertyChangedEventHandler PropertyChanged;
 
-        /// <summary>Whether to allow null value when <seealso cref="CopyFrom"/>.</summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        protected static bool AllowNullCopy { get; set; } = false;
-
         /// <summary>Copy properties of other ViewStyle to this.</summary>
         /// <param name="other">The other BindableProperty merge to this.</param>
         [EditorBrowsable(EditorBrowsableState.Never)]
@@ -73,30 +89,51 @@ namespace Tizen.NUI.Binding
                 {
                     nameToBindableProperty2.TryGetValue(keyValuePair.Key, out var bindableProperty);
 
-                    if (null != bindableProperty)
+                    if (null != bindableProperty && other.IsSet(bindableProperty))
                     {
                         object value = other.GetValue(bindableProperty);
-
-                        if (AllowNullCopy || null != value)
-                        {
-                            SetValue(keyValuePair.Value, value);
-                        }
+                        InternalSetValue(keyValuePair.Value, value);
                     }
                 }
             }
         }
 
         /// <summary>
+        /// Copy all binding from other object.
+        /// </summary>
+        /// <param name="other"></param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void CopyBindingRelationShip(BindableObject other)
+        {
+            if (null == other)
+            {
+                return;
+            }
+
+            foreach (var property in properties)
+            {
+                RemoveBinding(property.Key);
+            }
+
+            foreach (var property in other.properties)
+            {
+                if (null != property.Value.Binding)
+                {
+                    var binding = property.Value.Binding;
+                    other.RemoveBinding(property.Key);
+                    SetBinding(property.Key, binding);
+                }
+            }
+        }
+
+        /// <summary>
         /// Raised whenever the BindingContext property changes.
         /// </summary>
         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
         public event EventHandler BindingContextChanged;
 
-        internal void ClearValue(BindableProperty property, bool fromStyle)
-        {
-            ClearValue(property, fromStyle: fromStyle, checkAccess: true);
-        }
+        internal void ClearValue(BindableProperty property, bool fromStyle) => ClearValue(property, fromStyle: fromStyle, checkAccess: true);
 
         /// <summary>
         /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
@@ -146,6 +183,11 @@ namespace Tizen.NUI.Binding
             if (property == null)
                 throw new ArgumentNullException(nameof(property));
 
+            if (!IsBound && property.ValueGetter != null)
+            {
+                return property.ValueGetter(this);
+            }
+
             BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
 
             if (context == null)
@@ -165,7 +207,8 @@ namespace Tizen.NUI.Binding
         /// Removes a previously set binding.
         /// </summary>
         /// <param name="property">The BindableProperty from which to remove bindings.</param>
-        internal void RemoveBinding(BindableProperty property)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RemoveBinding(BindableProperty property)
         {
             if (property == null)
                 throw new ArgumentNullException(nameof(property));
@@ -184,23 +227,58 @@ namespace Tizen.NUI.Binding
         /// <param name="binding">The binding to set.</param>
         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public void SetBinding(BindableProperty targetProperty, BindingBase binding)
+        public void SetBinding(BindableProperty targetProperty, BindingBase binding) => SetBinding(targetProperty, binding, false);
+
+        /// Internal used, will never changed to not hidden.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual bool IsCreateByXaml
         {
-            SetBinding(targetProperty, binding, false);
+            get;
+            set;
         }
 
-        private bool isCreateByXaml = false;
-        /// Only used by the IL of xaml, will never changed to not hidden.
+        /// This will be public opened in next ACR.
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public virtual bool IsCreateByXaml
+        public void EnforceNotifyBindedInstance(BindableProperty property)
         {
-            get
+            if (null != property)
             {
-                return isCreateByXaml;
-            }
-            set
-            {
-                isCreateByXaml = value;
+                BindablePropertyContext context = GetOrCreateContext(property);
+                BindingBase binding = context.Binding;
+
+                var currentlyApplying = applying;
+
+                if (binding != null && !currentlyApplying)
+                {
+                    applying = true;
+                    binding.Apply(true);
+                    applying = false;
+                }
+
+                OnPropertyChanged(property.PropertyName);
+
+                PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
+
+                if (null != propertyGroup)
+                {
+                    foreach (var relativeProperty in propertyGroup)
+                    {
+                        if (relativeProperty != property)
+                        {
+                            var relativeContext = GetOrCreateContext(relativeProperty);
+                            var relativeBinding = relativeContext.Binding;
+
+                            if (null != relativeBinding)
+                            {
+                                applying = true;
+                                relativeBinding.Apply(true);
+                                applying = false;
+                            }
+
+                            OnPropertyChanged(relativeProperty.PropertyName);
+                        }
+                    }
+                }
             }
         }
 
@@ -214,7 +292,13 @@ namespace Tizen.NUI.Binding
         [EditorBrowsable(EditorBrowsableState.Never)]
         public void SetValue(BindableProperty property, object value)
         {
-            if (true == isCreateByXaml)
+            InternalSetValue(property, value);
+            ChangedPropertiesSetExcludingStyle.Add(property);
+        }
+
+        internal void InternalSetValue(BindableProperty property, object value)
+        {
+            if (true == IsBound)
             {
                 SetValue(property, value, false, true);
             }
@@ -224,28 +308,35 @@ namespace Tizen.NUI.Binding
                 {
                     throw new ArgumentNullException(nameof(property));
                 }
-                property.PropertyChanged?.Invoke(this, null, value);
+
+                object oldvalue = null;
+                BindablePropertyContext context = GetOrCreateContext(property);
+                if (null != context)
+                {
+                    context.Attributes |= BindableContextAttributes.IsManuallySet;
+                    oldvalue = context.Value;
+                    context.Value = value;
+                }
+
+                property.PropertyChanging?.Invoke(this, oldvalue, value);
+                property.PropertyChanged?.Invoke(this, oldvalue, value);
 
                 OnPropertyChanged(property.PropertyName);
+                OnPropertyChangedWithData(property);
             }
         }
 
-        internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
+        private HashSet<BindableProperty> changedPropertiesSetExcludingStyle;
+        internal protected HashSet<BindableProperty> ChangedPropertiesSetExcludingStyle
         {
-            if (property == null)
-                throw new ArgumentNullException(nameof(property));
-
-            if (true == isCreateByXaml)
+            get
             {
-                if (property.IsReadOnly)
-                    throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
+                if (null == changedPropertiesSetExcludingStyle)
+                {
+                    changedPropertiesSetExcludingStyle = new HashSet<BindableProperty>();
+                }
 
-                SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
-                    SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
-            }
-            else
-            {
-                property.PropertyChanged?.Invoke(this, null, value);
+                return changedPropertiesSetExcludingStyle;
             }
         }
 
@@ -282,7 +373,7 @@ namespace Tizen.NUI.Binding
             if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
                 return;
 
-            object oldContext = bindable._inheritedContext;
+            object oldContext = bindable.inheritedContext;
 
             if (ReferenceEquals(oldContext, value))
                 return;
@@ -293,11 +384,11 @@ namespace Tizen.NUI.Binding
             if (bpContext != null && bpContext.Binding != null)
             {
                 bpContext.Binding.Context = value;
-                bindable._inheritedContext = null;
+                bindable.inheritedContext = null;
             }
             else
             {
-                bindable._inheritedContext = value;
+                bindable.inheritedContext = value;
             }
 
             bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
@@ -305,14 +396,27 @@ namespace Tizen.NUI.Binding
         }
 
         /// <summary>
-        /// Apply the bindings to BindingContext.
+        /// Register the properties which can effect each other in Binding to same group.
         /// </summary>
-        /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
-        protected void ApplyBindings()
+        public static void RegisterPropertyGroup(BindableProperty property, HashSet<BindableProperty> group)
         {
-            ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
+            if (!PropertyToGroup.ContainsKey(property))
+            {
+                PropertyToGroup.Add(property, group);
+            }
+
+            if (null != group && !(group.Contains(property)))
+            {
+                group.Add(property);
+            }
         }
+        /// <summary>
+        /// Apply the bindings to BindingContext.
+        /// </summary>
+        /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected void ApplyBindings() => ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
 
         /// <summary>
         /// Override this method to execute an action when the BindingContext changes.
@@ -341,6 +445,12 @@ namespace Tizen.NUI.Binding
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
             => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
+        
+        /// <summary>
+        /// Method that is called when a bound property is changed.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected virtual void OnPropertyChangedWithData(BindableProperty prop) { }
 
         /// <summary>
         /// Unapplies all previously set bindings.
@@ -349,9 +459,8 @@ namespace Tizen.NUI.Binding
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected void UnapplyBindings()
         {
-            for (int i = 0, _propertiesCount = _properties.Count; i < _propertiesCount; i++)
+            foreach (var context in properties.Values)
             {
-                BindablePropertyContext context = _properties[i];
                 if (context.Binding == null)
                     continue;
 
@@ -378,10 +487,8 @@ namespace Tizen.NUI.Binding
         {
             var values = new object[2];
 
-            for (var i = 0; i < _properties.Count; i++)
+            foreach (var context in properties.Values)
             {
-                BindablePropertyContext context = _properties[i];
-
                 if (ReferenceEquals(context.Property, property0))
                 {
                     values[0] = context.Value;
@@ -416,10 +523,8 @@ namespace Tizen.NUI.Binding
         {
             var values = new object[3];
 
-            for (var i = 0; i < _properties.Count; i++)
+            foreach (var context in properties.Values)
             {
-                BindablePropertyContext context = _properties[i];
-
                 if (ReferenceEquals(context.Property, property0))
                 {
                     values[0] = context.Value;
@@ -458,9 +563,8 @@ namespace Tizen.NUI.Binding
         internal object[] GetValues(params BindableProperty[] properties)
         {
             var values = new object[properties.Length];
-            for (var i = 0; i < _properties.Count; i++)
+            foreach (var context in this.properties.Values)
             {
-                var context = _properties[i];
                 var index = properties.IndexOf(context.Property);
                 if (index < 0)
                     continue;
@@ -503,6 +607,8 @@ namespace Tizen.NUI.Binding
             if (fromStyle && !CanBeSetFromStyle(targetProperty))
                 return;
 
+            IsBound = true;
+
             var context = GetOrCreateContext(targetProperty);
             if (fromStyle)
                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
@@ -534,10 +640,7 @@ namespace Tizen.NUI.Binding
             return false;
         }
 
-        internal void SetDynamicResource(BindableProperty property, string key)
-        {
-            SetDynamicResource(property, key, false);
-        }
+        internal void SetDynamicResource(BindableProperty property, string key) => SetDynamicResource(property, key, false);
 
         internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
         {
@@ -559,14 +662,11 @@ namespace Tizen.NUI.Binding
             OnSetDynamicResource(property, key);
         }
 
-        internal void SetValue(BindableProperty property, object value, bool fromStyle)
-        {
-            SetValue(property, value, fromStyle, true);
-        }
+        internal void SetValue(BindableProperty property, object value, bool fromStyle) => SetValue(property, value, fromStyle, true);
 
         internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
         {
-            SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
+            SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None);
         }
 
         /// <summary>
@@ -576,12 +676,9 @@ namespace Tizen.NUI.Binding
         /// <param name="value">The value to set</param>
         /// <param name="attributes">The set value flag</param>
         [EditorBrowsable(EditorBrowsableState.Never)]
-        internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
-        {
-            SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
-        }
+        internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None) => SetValueCore(property, value, attributes, SetValuePrivateFlags.Default);
 
-        internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
+        internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
         {
             bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
             bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
@@ -599,7 +696,7 @@ namespace Tizen.NUI.Binding
 
             if (!converted && !property.TryConvert(ref value))
             {
-                Console.WriteLine("SetValue", "Can not convert {0} to type '{1}'", value, property.ReturnType);
+                Console.WriteLine($"SetValue : Can not convert {value} to type {property.ReturnType}");
                 return;
             }
 
@@ -616,13 +713,17 @@ namespace Tizen.NUI.Binding
                 context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
             }
             else
+            {
                 context.Attributes &= ~BindableContextAttributes.IsManuallySet;
+            }
 
             if (fromStyle)
+            {
                 context.Attributes |= BindableContextAttributes.IsSetFromStyle;
+            }
             // else omitted on purpose
 
-            bool currentlyApplying = _applying;
+            bool currentlyApplying = applying;
 
             if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
             {
@@ -635,7 +736,7 @@ namespace Tizen.NUI.Binding
             else
             {
                 context.Attributes |= BindableContextAttributes.IsBeingSet;
-                SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
+                SetValueActual(property, context, value, currentlyApplying, attributes, silent);
 
                 Queue<SetValueArgs> delayQueue = context.DelayedSetters;
                 if (delayQueue != null)
@@ -643,7 +744,7 @@ namespace Tizen.NUI.Binding
                     while (delayQueue.Count > 0)
                     {
                         SetValueArgs s = delayQueue.Dequeue();
-                        SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
+                        SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, s.Attributes);
                     }
 
                     context.DelayedSetters = null;
@@ -655,7 +756,7 @@ namespace Tizen.NUI.Binding
 
         internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
         {
-            var prop = _properties.ToArray();
+            var prop = properties.Values.ToArray();
             for (int i = 0, propLength = prop.Length; i < propLength; i++)
             {
                 BindablePropertyContext context = prop[i];
@@ -671,9 +772,49 @@ namespace Tizen.NUI.Binding
             }
         }
 
+        /// <summary>
+        /// Check if object is bound or not.
+        /// This API used for legacy codes.
+        /// Should be removed after all app usage replaced into IsBound.
+        /// </summary>
+        [Obsolete("This has been deprecated in API11. Use IsBound property instead.")]
+        internal bool IsBinded
+        {
+            get
+            {
+                return IsBound;
+            }
+            set
+            {
+                IsBound = value;
+            }
+        }
+
+        /// <summary>
+        /// Check if object is bound or not.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool IsBound
+        {
+            get;
+            set;
+        } = false;
+
+        static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
+        {
+            bindable.inheritedContext = null;
+            bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
+            bindable.OnBindingContextChanged();
+
+            if (newvalue is BindableObject targetBindableObject)
+            {
+                targetBindableObject.IsBound = true;
+            }
+        }
+
         static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
         {
-            object context = bindable._inheritedContext;
+            object context = bindable.inheritedContext;
             var oldBinding = oldBindingBase as Binding;
             var newBinding = newBindingBase as Binding;
 
@@ -683,13 +824,6 @@ namespace Tizen.NUI.Binding
                 newBinding.Context = context;
         }
 
-        static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
-        {
-            bindable._inheritedContext = null;
-            bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
-            bindable.OnBindingContextChanged();
-        }
-
         void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
         {
             if (property == null)
@@ -727,6 +861,7 @@ namespace Tizen.NUI.Binding
             if (!same)
             {
                 OnPropertyChanged(property.PropertyName);
+                OnPropertyChangedWithData(property);
                 property.PropertyChanged?.Invoke(this, original, newValue);
             }
         }
@@ -741,24 +876,12 @@ namespace Tizen.NUI.Binding
             else
                 context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
 
-            _properties.Add(context);
+            properties.Add(property, context);
             return context;
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        BindablePropertyContext GetContext(BindableProperty property)
-        {
-            List<BindablePropertyContext> properties = _properties;
-
-            for (var i = 0; i < properties.Count; i++)
-            {
-                BindablePropertyContext context = properties[i];
-                if (ReferenceEquals(context.Property, property))
-                    return context;
-            }
-
-            return null;
-        }
+        BindablePropertyContext GetContext(BindableProperty property) => properties.TryGetValue(property, out var result) ? result : null;
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         BindablePropertyContext GetOrCreateContext(BindableProperty property)
@@ -768,7 +891,11 @@ namespace Tizen.NUI.Binding
             {
                 context = CreateAndAddContext(property);
             }
-            else if (property.DefaultValueCreator != null)
+            else if (property.ValueGetter != null)
+            {
+                context.Value = property.ValueGetter(this); //Update Value from dali
+            }//added by xiaohui.fang
+            else if (property.DefaultValueCreator != null) //This will be removed in the future.
             {
                 context.Value = property.DefaultValueCreator(this); //Update Value from dali
             }//added by xb.teng
@@ -785,7 +912,7 @@ namespace Tizen.NUI.Binding
             context.Binding = null;
         }
 
-        void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
+        internal void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
         {
             if (property == null)
                 throw new ArgumentNullException(nameof(property));
@@ -797,11 +924,10 @@ namespace Tizen.NUI.Binding
                 return;
 
             SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
-                (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
-                false);
+                (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0));
         }
 
-        void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
+        void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes, bool silent = false)
         {
             object original = context.Value;
             bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
@@ -838,35 +964,49 @@ namespace Tizen.NUI.Binding
                 }
             }
 
-            if (!silent)
+            PropertyToGroup.TryGetValue(property, out HashSet<BindableProperty> propertyGroup);
+
+            if (!silent && (!same || raiseOnEqual))
             {
-                if ((!same || raiseOnEqual))
+                property.PropertyChanged?.Invoke(this, original, value);
+
+                if (binding != null && !currentlyApplying)
                 {
-                    property.PropertyChanged?.Invoke(this, original, value);
+                    applying = true;
+                    binding.Apply(true);
+                    applying = false;
+                }
 
-                    if (binding != null && !currentlyApplying)
-                    {
-                        _applying = true;
-                        binding.Apply(true);
-                        _applying = false;
-                    }
+                OnPropertyChanged(property.PropertyName);
 
-                    OnPropertyChanged(property.PropertyName);
-                }
-                else if (true == same && true == forceSendChangeSignal)
+                if (null != propertyGroup)
                 {
-                    if (binding != null && !currentlyApplying)
+                    foreach (var relativeProperty in propertyGroup)
                     {
-                        _applying = true;
-                        binding.Apply(true);
-                        _applying = false;
-                    }
+                        if (relativeProperty != property)
+                        {
+                            var relativeContext = GetOrCreateContext(relativeProperty);
+                            var relativeBinding = relativeContext.Binding;
+
+                            if (null != relativeBinding)
+                            {
+                                applying = true;
+                                relativeBinding.Apply(true);
+                                applying = false;
+                            }
 
-                    OnPropertyChanged(property.PropertyName);
+                            OnPropertyChanged(relativeProperty.PropertyName);
+                        }
+                    }
                 }
+
+                OnPropertyChangedWithData(property);
             }
         }
 
+        private static Dictionary<BindableProperty, HashSet<BindableProperty>> PropertyToGroup { get; }
+            = new Dictionary<BindableProperty, HashSet<BindableProperty>>();
+
         [Flags]
         enum BindableContextAttributes
         {
@@ -916,6 +1056,60 @@ namespace Tizen.NUI.Binding
                 Attributes = attributes;
             }
         }
+
+        internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
+        {
+            var xElementToNameOfOld = new Dictionary<object, string>();
+
+            foreach (var pair in oldNameScope)
+            {
+                xElementToNameOfOld.Add(pair.Value, pair.Key);
+            }
+
+            foreach (var property in properties)
+            {
+                if (property.Value.Binding is Binding binding && null != binding.Source)
+                {
+                    string xName;
+                    xElementToNameOfOld.TryGetValue(binding.Source, out xName);
+
+                    if (null != xName)
+                    {
+                        var newObject = newNameScope[xName];
+                        binding.Unapply();
+                        binding.Source = newObject;
+                        SetBinding(property.Key, binding);
+                    }
+                }
+            }
+
+            if (null != BindingContext)
+            {
+                string xName;
+                xElementToNameOfOld.TryGetValue(BindingContext, out xName);
+
+                if (null != xName)
+                {
+                    var newObject = newNameScope[xName];
+                    BindingContext = newObject;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Unapplies all previously set bindings.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void ClearBinding()
+        {
+            foreach (var property in properties)
+            {
+                if (null != property.Value.Binding)
+                {
+                    property.Value.Binding.Unapply();
+                }
+            }
+        }
     }
 }