[NUI]Fix ResourcesDictionary & BindingContext issues
authorXianbing Teng <xb.teng@samsung.com>
Thu, 17 Feb 2022 10:03:47 +0000 (18:03 +0800)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Wed, 23 Feb 2022 08:23:38 +0000 (17:23 +0900)
Description:
1. Optimize codes of xaml parser.
2. Split resources from Application, each view can has its own resources. Previously only use application resources, it costs more time to lookup.
3. Migrate XamlStyle/XamlResources from View/Layer to Container. Previously both Layer and View have XamlStyle and XamlResources properties, it is redundant.
4. Optimize inherited binding context.
5. This change does not change the previous use.

24 files changed:
src/Tizen.NUI/src/internal/Application/Application.cs
src/Tizen.NUI/src/internal/Xaml/ApplyPropertiesVisitor.cs
src/Tizen.NUI/src/internal/Xaml/CreateValuesVisitor.cs
src/Tizen.NUI/src/internal/Xaml/FillResourceDictionariesVisitor.cs
src/Tizen.NUI/src/internal/Xaml/IResourcesLoader.cs
src/Tizen.NUI/src/internal/Xaml/ResourcesLoader.cs
src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs
src/Tizen.NUI/src/internal/XamlBinding/Internals/ResourceLoader.cs
src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs
src/Tizen.NUI/src/internal/XamlBinding/ResourcesExtensions.cs
src/Tizen.NUI/src/public/BaseComponents/View.cs
src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
src/Tizen.NUI/src/public/BaseComponents/ViewPublicMethods.cs
src/Tizen.NUI/src/public/Common/BaseHandle.cs [changed mode: 0644->0755]
src/Tizen.NUI/src/public/Common/Container.cs
src/Tizen.NUI/src/public/Common/Layer.cs
src/Tizen.NUI/src/public/Xaml/XamlFilePathAttribute.cs
src/Tizen.NUI/src/public/Xaml/XamlParseException.cs
src/Tizen.NUI/src/public/XamlBinding/BindableObject.cs
src/Tizen.NUI/src/public/XamlBinding/Element.cs
src/Tizen.NUI/src/public/XamlBinding/IValueConverter.cs
src/Tizen.NUI/src/public/XamlBinding/ResourceDictionary.cs
src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs

index ac87ddc..73430e0 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -308,12 +308,9 @@ namespace Tizen.NUI
 
         public delegate void resChangeCb(object sender, ResourcesChangedEventArgs e);
 
-        internal event EventHandler<ResourcesChangedEventArgs> XamlResourceChanged;
-
         internal override void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
         {
             base.OnResourcesChanged(sender, e);
-            XamlResourceChanged?.Invoke(sender, e);
         }
 
         public ResourceDictionary XamlResources
@@ -358,6 +355,9 @@ namespace Tizen.NUI
 
         internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
         {
+            if (values == null)
+                return;
+
             if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
             {
                 base.OnParentResourcesChanged(values);
@@ -373,7 +373,8 @@ namespace Tizen.NUI
                 if (innerKeys.Add(value.Key))
                     changedResources.Add(value);
             }
-            OnResourcesChanged(changedResources);
+            if (changedResources.Count != 0)
+                OnResourcesChanged(changedResources);
         }
 
         internal Application(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
index 0ca6d91..e1af6ff 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -53,13 +53,14 @@ namespace Tizen.NUI.Xaml
         public bool StopOnResourceDictionary { get; }
         public bool VisitNodeOnDataTemplate => true;
         public bool SkipChildren(INode node, INode parentNode) => false;
-        public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
+        public bool IsResourceDictionary(ElementNode node) => Context.Types.TryGetValue(node, out var type) && typeof(ResourceDictionary).IsAssignableFrom(type);
 
         public void Visit(ValueNode node, INode parentNode)
         {
             var parentElement = parentNode as IElementNode;
             var value = Values[node];
-            var source = Values[parentNode];
+            if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
+                return;
             XmlName propertyName;
 
             if (TryGetPropertyName(node, parentNode, out propertyName))
@@ -119,7 +120,8 @@ namespace Tizen.NUI.Xaml
                 parentElement = parentNode as IElementNode;
             }
 
-            var value = Values[node];
+            if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
+                return;
 
             if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
             {
@@ -130,13 +132,15 @@ namespace Tizen.NUI.Xaml
                 if (parentElement.SkipProperties.Contains(propertyName))
                     return;
 
-                var source = Values[parentNode];
+                if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
+                    return;
                 ProvideValue(ref value, node, source, propertyName);
                 SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
             }
             else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
             {
-                var source = Values[parentNode];
+                if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
+                    return;
                 ProvideValue(ref value, node, source, XmlName.Empty);
                 string contentProperty;
                 Exception xpe = null;
@@ -189,11 +193,13 @@ namespace Tizen.NUI.Xaml
                 xpe = xpe ?? new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
                 if (Context.ExceptionHandler != null)
                     Context.ExceptionHandler(xpe);
-                throw xpe;
+                else
+                    throw xpe;
             }
             else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
             {
-                var source = Values[parentNode.Parent];
+                if (!Values.TryGetValue(parentNode.Parent, out var source) && Context.ExceptionHandler != null)
+                    return;
                 ProvideValue(ref value, node, source, XmlName.Empty);
                 var parentList = (ListNode)parentNode;
                 if (Skips.Contains(parentList.XmlName))
@@ -285,11 +291,17 @@ namespace Tizen.NUI.Xaml
             {
                 (serviceProvider.IProvideValueTarget as XamlValueTargetProvider).TargetProperty = GetTargetProperty(source, propertyName, Context, node);
             }
-
-            if (markupExtension != null)
-                value = markupExtension.ProvideValue(serviceProvider);
-            else if (valueProvider != null)
-                value = valueProvider.ProvideValue(serviceProvider);
+            try {
+                if (markupExtension != null)
+                    value = markupExtension.ProvideValue(serviceProvider);
+                else if (valueProvider != null)
+                    value = valueProvider.ProvideValue(serviceProvider);
+            } catch (Exception e) {
+                if (Context.ExceptionHandler != null)
+                    Context.ExceptionHandler(e);
+                else
+                    throw;
+            }
         }
 
         static string GetContentPropertyName(IEnumerable<CustomAttributeData> attributes)
@@ -722,6 +734,8 @@ namespace Tizen.NUI.Xaml
 
             if (xKey != null)
                 resourceDictionary.Add(xKey, value);
+            else if (value is XamlStyle)
+                resourceDictionary.Add((XamlStyle)value);
             else if (value is ResourceDictionary)
                 resourceDictionary.Add((ResourceDictionary)value);
             else
index d9f70ae..9336e8b 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -161,11 +161,6 @@ namespace Tizen.NUI.Xaml
                         }
                         if (value is Element element)
                         {
-                            if (null != Application.Current)
-                            {
-                                Application.Current.XamlResourceChanged += element.OnResourcesChanged;
-                            }
-
                             element.IsCreateByXaml = true;
                         }
                     }
@@ -286,11 +281,6 @@ namespace Tizen.NUI.Xaml
                 object ret = Activator.CreateInstance(nodeType, BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding, null, arguments, CultureInfo.CurrentCulture);
                 if (ret is Element element)
                 {
-                    if (null != Application.Current)
-                    {
-                        Application.Current.XamlResourceChanged += element.OnResourcesChanged;
-                    }
-
                     element.IsCreateByXaml = true;
                 }
                 return ret;
@@ -426,11 +416,6 @@ namespace Tizen.NUI.Xaml
                 value = Activator.CreateInstance(nodeType);
                 if (value is Element element)
                 {
-                    if (null != Application.Current)
-                    {
-                        Application.Current.XamlResourceChanged += element.OnResourcesChanged;
-                    }
-
                     element.IsCreateByXaml = true;
                 }
             }
index 2b8abe8..eeae4f2 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -42,7 +42,7 @@ namespace Tizen.NUI.Xaml
 
         public void Visit(ValueNode node, INode parentNode)
         {
-            if (!typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)]))
+                       if (!Context.Types.TryGetValue((IElementNode)parentNode, out var type) || !typeof(ResourceDictionary).IsAssignableFrom(type))
                 return;
 
             node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
@@ -54,13 +54,14 @@ namespace Tizen.NUI.Xaml
 
         public void Visit(ElementNode node, INode parentNode)
         {
-            var value = Values[node];
+            if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
+                               return;
             XmlName propertyName;
             //Set RD to VE
             if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName))
             {
-                if ((propertyName.LocalName == "Resources" ||
-                     propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && value is ResourceDictionary)
+                if ((propertyName.LocalName == "XamlResources" ||
+                     propertyName.LocalName.EndsWith(".XamlResources", StringComparison.Ordinal)) && value is ResourceDictionary)
                 {
                     var source = Values[parentNode];
                     ApplyPropertiesVisitor.SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
@@ -70,7 +71,8 @@ namespace Tizen.NUI.Xaml
 
             //Only proceed further if the node is a keyless RD
             if (parentNode is IElementNode
-                && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])
+                               && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType)
+                               && typeof(ResourceDictionary).IsAssignableFrom(parentType)
                 && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
                 node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
             else if (parentNode is ListNode
@@ -93,7 +95,8 @@ namespace Tizen.NUI.Xaml
             if (enode is null)
                 return false;
             if (parentNode is IElementNode
-                && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])
+                               && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType)
+                               && typeof(ResourceDictionary).IsAssignableFrom(parentType)
                 && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
                 return true;
             if (parentNode is ListNode
index 8ea6349..732f23d 100755 (executable)
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+/*
+ * 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.
@@ -25,6 +25,6 @@ namespace Tizen.NUI
     internal interface IResourcesLoader
     {
         T CreateFromResource<T>(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo) where T : new();
-        string GetResource(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo);
+        string GetResource(string resourcePath, Assembly assembly, object target, IXmlLineInfo lineInfo);
     }
 }
index 14cd470..433743f 100755 (executable)
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+/*
+ * 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.
@@ -28,10 +28,16 @@ namespace Tizen.NUI.Xaml
     {
         public T CreateFromResource<T>(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo) where T : new()
         {
-            var alternateResource = ResourceLoader.ResourceProvider?.Invoke(assembly.GetName(), resourcePath);
+            var rd = new T();
+            var resourceLoadingResponse = ResourceLoader.ResourceProvider?.Invoke(new ResourceLoader.ResourceLoadingQuery
+            {
+                AssemblyName = assembly.GetName(),
+                ResourcePath = resourcePath,
+                Instance = rd
+            });
+            var alternateResource = resourceLoadingResponse?.ResourceContent;
             if (alternateResource != null)
             {
-                var rd = new T();
                 rd.LoadFromXaml(alternateResource);
                 return rd;
             }
@@ -46,16 +52,20 @@ namespace Tizen.NUI.Xaml
                     throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo);
                 using (var reader = new StreamReader(stream))
                 {
-                    var rd = new T();
                     rd.LoadFromXaml(reader.ReadToEnd());
                     return rd;
                 }
             }
         }
 
-        public string GetResource(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo)
+        public string GetResource(string resourcePath, Assembly assembly, object target, IXmlLineInfo lineInfo)
         {
-            var alternateResource = ResourceLoader.ResourceProvider?.Invoke(assembly.GetName(), resourcePath);
+            var resourceLoadingResponse = ResourceLoader.ResourceProvider?.Invoke(new ResourceLoader.ResourceLoadingQuery {
+                AssemblyName = assembly.GetName(),
+                ResourcePath = resourcePath,
+                Instance = target
+            });
+            var alternateResource = resourceLoadingResponse?.ResourceContent;
             if (alternateResource != null)
                 return alternateResource;
 
index 37078b6..b999ccb 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -129,11 +129,13 @@ namespace Tizen.NUI.Xaml
 
                     var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), ret, (IXmlNamespaceResolver)reader);
                     XamlParser.ParseXaml(rootnode, reader);
+                    var doNotThrow = ResourceLoader.ExceptionHandler != null || Internals.XamlLoader.DoNotThrowOnExceptions;
+                    void ehandler(Exception e) => ResourceLoader.ExceptionHandler?.Invoke((e, path));
                     Visit(rootnode, new HydrationContext
                     {
                         RootElement = ret,
 #pragma warning disable 0618
-                        ExceptionHandler = ResourceLoader.ExceptionHandler ?? (Internals.XamlLoader.DoNotThrowOnExceptions ? e => { } : (Action<Exception>)null)
+                        ExceptionHandler = doNotThrow ? ehandler : (Action<Exception>)null
 #pragma warning restore 0618
                     });
                     break;
@@ -177,11 +179,13 @@ namespace Tizen.NUI.Xaml
 
                     var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), view, (IXmlNamespaceResolver)reader);
                     XamlParser.ParseXaml(rootnode, reader);
+                    var doNotThrow = ResourceLoader.ExceptionHandler != null || Internals.XamlLoader.DoNotThrowOnExceptions;
+                    void ehandler(Exception e) => ResourceLoader.ExceptionHandler?.Invoke((e, XamlFilePathAttribute.GetFilePathForObject(view)));
                     Visit(rootnode, new HydrationContext
                     {
                         RootElement = view,
 #pragma warning disable 0618
-                        ExceptionHandler = ResourceLoader.ExceptionHandler ?? (Internals.XamlLoader.DoNotThrowOnExceptions ? e => { } : (Action<Exception>)null)
+                        ExceptionHandler = doNotThrow ? ehandler : (Action<Exception>)null
 #pragma warning restore 0618
                     });
                     break;
index 7c20e06..3910c7e 100755 (executable)
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+/*
+ * 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.
@@ -23,29 +23,39 @@ namespace Tizen.NUI.Binding.Internals
 {
     internal static class ResourceLoader
     {
-        static Func<AssemblyName, string, string> resourceProvider = (asmName, path) =>
-        {
-            if (typeof(Theme).Assembly.GetName().FullName != asmName.FullName)
+        static Func<ResourceLoadingQuery, ResourceLoadingResponse> _resourceProvider = (resourceLoadingQuery) => {
+            if (typeof(Theme).Assembly.GetName().FullName != resourceLoadingQuery.AssemblyName.FullName)
             {
                 string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
-                path = resource + path;
+                resourceLoadingQuery.ResourcePath = resource + resourceLoadingQuery.ResourcePath;
             }
 
-            string ret = File.ReadAllText(path);
-            return ret;
+            string ret = File.ReadAllText(resourceLoadingQuery.ResourcePath);
+            return new ResourceLoadingResponse { ResourceContent = ret };
         };
-
-        //takes a resource path, returns string content
-        public static Func<AssemblyName, string, string> ResourceProvider
+        public static Func<ResourceLoadingQuery, ResourceLoadingResponse> ResourceProvider
         {
-            get => resourceProvider;
+            get => _resourceProvider;
             internal set
             {
-                DesignMode.IsDesignModeEnabled = true;
-                resourceProvider = value;
+                DesignMode.IsDesignModeEnabled = value != null;
+                _resourceProvider = value;
             }
         }
 
-        internal static Action<Exception> ExceptionHandler { get; set; }
+        internal static Action<(Exception exception, string filepath)> ExceptionHandler { get; set; }
+
+        public class ResourceLoadingQuery
+        {
+            public AssemblyName AssemblyName { get; set; }
+            public string ResourcePath { get; set; }
+            public object Instance { get; set; }
+        }
+
+        public class ResourceLoadingResponse
+        {
+            public string ResourceContent { get; set; }
+            public bool UseDesignProperties { get; set; }
+        }
     }
 }
index ebf6439..22572f1 100755 (executable)
@@ -36,7 +36,14 @@ namespace Tizen.NUI.Binding
         public IStyle Style
         {
             get { return style; }
-            set { SetStyle(ImplicitStyle, ClassStyles, value); }
+            set
+            {
+                if (style == value)
+                    return;
+                if (value != null && !value.TargetType.IsAssignableFrom(TargetType))
+                    NUILog.Error($"Style TargetType {value.TargetType.FullName} is not compatible with element target type {TargetType}");
+                SetStyle(ImplicitStyle, ClassStyles, value);
+            }
         }
 
         public IList<string> StyleClass
@@ -47,7 +54,7 @@ namespace Tizen.NUI.Binding
                 if (styleClass == value)
                     return;
 
-                if (styleClass != null && classStyles != null)
+                if (styleClass != null && classStyleProperties != null)
                     foreach (var classStyleProperty in classStyleProperties)
                         Target.RemoveDynamicResource(classStyleProperty);
 
index b0ccc27..ad6e6ea 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -39,8 +39,13 @@ namespace Tizen.NUI.Binding
                     if (ve.XamlResources != null)
                     {
                         foreach (KeyValuePair<string, object> res in ve.XamlResources.MergedResources)
-                            if (!resources.ContainsKey(res.Key))
-                                resources.Add(res.Key, res.Value);
+                        {
+                            // If a MergedDictionary value is overridden for a DynamicResource, 
+                            // it comes out later in the enumeration of MergedResources
+                            // TryGetValue ensures we pull the up-to-date value for the key
+                            if (!resources.ContainsKey(res.Key) && ve.XamlResources.TryGetValue(res.Key, out object value))
+                                resources.Add(res.Key, value);
+                        }
                     }
                 }
 
index f00d363..151e709 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -257,30 +257,6 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
-        /// 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 bool IsResourcesCreated
-        {
-            get
-            {
-                return Application.Current.IsResourcesCreated;
-            }
-        }
-
-        /// 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 ResourceDictionary XamlResources
-        {
-            get
-            {
-                return Application.Current.XamlResources;
-            }
-            set
-            {
-                Application.Current.XamlResources = value;
-            }
-        }
-
         /// <summary>
         /// The StyleName, type string.
         /// The value indicates DALi style name defined in json theme file.
@@ -2396,19 +2372,6 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public XamlStyle XamlStyle
-        {
-            get
-            {
-                return (XamlStyle)GetValue(XamlStyleProperty);
-            }
-            set
-            {
-                SetValue(XamlStyleProperty, value);
-            }
-        }
-
         /// <summary>
         /// The Color of View. This is an RGBA value.
         /// </summary>
index 755a331..ffb81e4 100755 (executable)
@@ -1705,12 +1705,6 @@ namespace Tizen.NUI.BaseComponents
         });
 
         /// <summary>
-        /// XamlStyleProperty
-        /// </summary>
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public static readonly BindableProperty XamlStyleProperty = BindableProperty.Create(nameof(XamlStyle), typeof(XamlStyle), typeof(View), default(XamlStyle), propertyChanged: (bindable, oldvalue, newvalue) => ((View)bindable).MergedStyle.Style = (XamlStyle)newvalue);
-
-        /// <summary>
         /// EnableControlState property
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
index fa912ef..4fb9504 100755 (executable)
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+/*
+ * 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.
  */
 
 using System;
-using System.Collections.Generic;
 using System.ComponentModel;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using Tizen.NUI.Binding;
 
 namespace Tizen.NUI.BaseComponents
 {
@@ -30,21 +26,8 @@ namespace Tizen.NUI.BaseComponents
     /// <since_tizen> 3 </since_tizen>
     public partial class View
     {
-        private MergedStyle mergedStyle = null;
         internal string styleName;
 
-        internal MergedStyle MergedStyle
-        {
-            get
-            {
-                if (null == mergedStyle)
-                {
-                    mergedStyle = new MergedStyle(GetType(), this);
-                }
-
-                return mergedStyle;
-            }
-        }
         internal virtual LayoutItem CreateDefaultLayout()
         {
             return new AbsoluteLayout();
@@ -993,8 +976,7 @@ namespace Tizen.NUI.BaseComponents
             Children.Remove(child);
             child.InternalParent = null;
 
-            RemoveChildBindableObject(child);
-
+            OnChildRemoved(child);
             if (ChildRemoved != null)
             {
                 ChildRemovedEventArgs e = new ChildRemovedEventArgs
index 1d7dac3..84bc781 100755 (executable)
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2020 Samsung Electronics Co., Ltd.
+/*
+ * 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.
@@ -157,6 +157,7 @@ namespace Tizen.NUI.BaseComponents
                 if (NDalicPINVOKE.SWIGPendingException.Pending)
                     throw NDalicPINVOKE.SWIGPendingException.Retrieve();
                 Children.Add(child);
+                OnChildAdded(child);
 
                 if (ChildAdded != null)
                 {
@@ -166,8 +167,6 @@ namespace Tizen.NUI.BaseComponents
                     };
                     ChildAdded(this, e);
                 }
-
-                AddChildBindableObject(child);
             }
         }
 
old mode 100644 (file)
new mode 100755 (executable)
index 0b594fe..909138a
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -538,11 +538,6 @@ namespace Tizen.NUI
             }
 
             disposed = true;
-
-            if (null != Application.Current)
-            {
-                Application.Current.XamlResourceChanged -= OnResourcesChanged;
-            }
         }
 
         /// <summary>
index 799251c..90444ab 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -17,7 +17,9 @@
 
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
 
 namespace Tizen.NUI
 {
@@ -26,16 +28,76 @@ namespace Tizen.NUI
     /// added to them.
     /// </summary>
     /// <since_tizen> 4 </since_tizen>
-    public abstract class Container : Animatable
+    public abstract class Container : Animatable, IResourcesProvider
     {
+        /// <summary> XamlStyleProperty </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty XamlStyleProperty = BindableProperty.Create(nameof(XamlStyle), typeof(XamlStyle), typeof(Container), default(XamlStyle), propertyChanged: (bindable, oldvalue, newvalue) => ((View)bindable).MergedStyle.Style = (XamlStyle)newvalue);
+
         internal BaseHandle InternalParent;
         private List<View> childViews = new List<View>();
+        private MergedStyle mergedStyle = null;
+        ResourceDictionary _resources;
+        bool IResourcesProvider.IsResourcesCreated => _resources != null;
 
         internal Container(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
         {
             // No un-managed data hence no need to store a native ptr
         }
 
+        /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ResourceDictionary XamlResources
+        {
+            get
+            {
+                if (_resources != null)
+                    return _resources;
+                _resources = new ResourceDictionary();
+                ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+                return _resources;
+            }
+            set
+            {
+                if (_resources == value)
+                    return;
+                OnPropertyChanging();
+                if (_resources != null)
+                    ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
+                _resources = value;
+                OnResourcesChanged(value);
+                if (_resources != null)
+                    ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+                OnPropertyChanged();
+            }
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public XamlStyle XamlStyle
+        {
+            get
+            {
+                return (XamlStyle)GetValue(XamlStyleProperty);
+            }
+            set
+            {
+                SetValue(XamlStyleProperty, value);
+            }
+        }
+
+        internal MergedStyle MergedStyle
+        {
+            get
+            {
+                if (null == mergedStyle)
+                {
+                    mergedStyle = new MergedStyle(GetType(), this);
+                }
+
+                return mergedStyle;
+            }
+        }
+
         /// <summary>
         /// List of children of Container.
         /// </summary>
@@ -125,5 +187,54 @@ namespace Tizen.NUI
         public abstract UInt32 GetChildCount();
 
         internal abstract View FindCurrentChildById(uint id);
+
+        internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
+        {
+            if (values == null)
+                return;
+
+            if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
+            {
+                base.OnParentResourcesChanged(values);
+                return;
+            }
+
+            var innerKeys = new HashSet<string>();
+            var changedResources = new List<KeyValuePair<string, object>>();
+            foreach (KeyValuePair<string, object> c in XamlResources)
+                innerKeys.Add(c.Key);
+            foreach (KeyValuePair<string, object> value in values)
+            {
+                if (innerKeys.Add(value.Key))
+                    changedResources.Add(value);
+            }
+            if (changedResources.Count != 0)
+                OnResourcesChanged(changedResources);
+        }
+
+        /// <summary>
+        /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
+        /// </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 override void OnBindingContextChanged()
+        {
+            var gotBindingContext = false;
+            object bc = null;
+
+            for (var index = 0; index < Children.Count; index++)
+            {
+                Element child = Children[index];
+
+                if (!gotBindingContext)
+                {
+                    bc = BindingContext;
+                    gotBindingContext = true;
+                }
+
+                SetChildInheritedBindingContext(child, bc);
+            }
+            base.OnBindingContextChanged();
+        }
     }
 } // namespace Tizen.NUI
index 494286b..6f18d36 100755 (executable)
@@ -17,7 +17,6 @@
 using System;
 using Tizen.NUI.BaseComponents;
 using System.ComponentModel;
-using Tizen.NUI.Binding;
 
 namespace Tizen.NUI
 {
@@ -242,20 +241,6 @@ namespace Tizen.NUI
             }
         }
 
-        /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public ResourceDictionary XamlResources
-        {
-            get
-            {
-                return Application.Current.XamlResources;
-            }
-            set
-            {
-                Application.Current.XamlResources = value;
-            }
-        }
-
         /// <summary>
         /// Gets the Layer's ID
         /// Readonly
@@ -303,7 +288,7 @@ namespace Tizen.NUI
                 if (NDalicPINVOKE.SWIGPendingException.Pending)
                     throw NDalicPINVOKE.SWIGPendingException.Retrieve();
                 Children.Add(child);
-                BindableObject.SetInheritedBindingContext(child, this?.BindingContext);
+                OnChildAdded(child);
             }
         }
 
@@ -326,6 +311,7 @@ namespace Tizen.NUI
 
             Children.Remove(child);
             child.InternalParent = null;
+            OnChildRemoved(child);
         }
 
         /// <summary>
index 3e90165..dcbe7c8 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -17,6 +17,8 @@
 
 using System;
 using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
 using System.Runtime.CompilerServices;
 
 namespace Tizen.NUI.Xaml
@@ -28,10 +30,11 @@ namespace Tizen.NUI.Xaml
     {
         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public XamlFilePathAttribute([CallerFilePath] string filePath = "")
-        {
-            // Unused parameter
-            _ = filePath;
-        }
+        public XamlFilePathAttribute([CallerFilePath] string filePath = "") => FilePath = filePath;
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string FilePath { get; }
+
+        internal static string GetFilePathForObject(object view) => (view?.GetType().GetTypeInfo().GetCustomAttributes(typeof(XamlFilePathAttribute), false).FirstOrDefault() as XamlFilePathAttribute)?.FilePath;
     }
 }
index da1c3f5..168bbba 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -72,6 +72,11 @@ namespace Tizen.NUI.Xaml
             XmlInfo = xmlInfo;
         }
 
+        internal XamlParseException(string message, IServiceProvider serviceProvider, Exception innerException = null)
+            : this(message, GetLineInfo(serviceProvider), innerException)
+        {
+        }
+
         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
         public IXmlLineInfo XmlInfo { get; private set; }
@@ -87,5 +92,9 @@ namespace Tizen.NUI.Xaml
                 return message;
             return string.Format("Position {0}:{1}. {2}", xmlinfo.LineNumber, xmlinfo.LinePosition, message);
         }
+
+
+        static IXmlLineInfo GetLineInfo(IServiceProvider serviceProvider)
+            => (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) is IXmlLineInfoProvider lineInfoProvider) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
     }
 }
index 7fe28e9..cfed29f 100755 (executable)
@@ -1,5 +1,5 @@
-/*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+/*
+ * 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.
@@ -36,36 +36,8 @@ namespace Tizen.NUI.Binding
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public static readonly BindableProperty BindingContextProperty =
-            BindableProperty.Create(nameof(BindingContext), typeof(object), typeof(BindableObject), null, propertyChanged: (BindableProperty.BindingPropertyChangedDelegate)((bindable, oldValue, newValue) =>
-            {
-                var bindableObject = (BindableObject)bindable;
-                if (newValue != null)
-                {
-                    bindableObject.bindingContext = newValue;
-                    bindableObject.FlushBinding();
-
-                    if (newValue is BindableObject targetBindableObject)
-                    {
-                        targetBindableObject.IsBinded = true;
-                    }
-                }
-            }),
-            defaultValueCreator: (BindableProperty.CreateDefaultValueDelegate)((bindable) =>
-            {
-                if (null != bindable.bindingContext)
-                {
-                    return bindable.bindingContext;
-                }
-
-                if (bindable is Container container)
-                {
-                    return container.Parent?.BindingContext;
-                }
-                else
-                {
-                    return null;
-                }
-            }));
+            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);
 
@@ -764,6 +736,18 @@ namespace Tizen.NUI.Binding
             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.IsBinded = true;
+            }
+        }
+
         static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
         {
             object context = bindable.inheritedContext;
@@ -1052,33 +1036,6 @@ namespace Tizen.NUI.Binding
                 Attributes = attributes;
             }
         }
-
-        internal void AddChildBindableObject(BindableObject child)
-        {
-            if (null != child)
-            {
-                children.Add(child);
-                child.FlushBinding();
-            }
-        }
-
-        internal void RemoveChildBindableObject(BindableObject child)
-        {
-            children.Remove(child);
-        }
-
-        private List<BindableObject> children = new List<BindableObject>();
-
-        private void FlushBinding()
-        {
-            ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
-            OnBindingContextChanged();
-
-            foreach (var child in children)
-            {
-                child.FlushBinding();
-            }
-        }
     }
 }
 
index 18a0ea0..79f4f7f 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -442,10 +442,7 @@ namespace Tizen.NUI.Binding
 
         internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
         {
-            // if (e == ResourcesChangedEventArgs.StyleSheets)
-            //         // ApplyStyleSheetsOnParentSet();
-            // else
-            //         OnParentResourcesChanged(e.Values);
+            OnParentResourcesChanged(e.Values);
         }
 
         internal virtual void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
@@ -514,11 +511,6 @@ namespace Tizen.NUI.Binding
             object value;
             if (this.TryGetResource(key, out value))
                 OnResourceChanged(property, value);
-
-            if (null != Application.Current)
-            {
-                Application.Current.XamlResourceChanged += OnResourcesChanged;
-            }
         }
 
         internal event EventHandler ParentSet;
index 1ee2a5d..937ff82 100755 (executable)
@@ -1,4 +1,4 @@
-/*
+/*
  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
index 797436b..1051090 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -25,8 +25,6 @@ using System.Globalization;
 using System.Linq;
 using System.Reflection;
 using System.Runtime.CompilerServices;
-
-using Tizen.NUI.Binding.Internals;
 using Tizen.NUI.Xaml;
 
 namespace Tizen.NUI.Binding
index 64edce2..f1a9d74 100755 (executable)
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Reflection;
 using Tizen.NUI.StyleSheets;
 using System.ComponentModel;
+using Tizen.NUI.BaseComponents;
 
 namespace Tizen.NUI.Binding
 {
@@ -12,6 +13,9 @@ namespace Tizen.NUI.Binding
     {
         internal const string StyleClassPrefix = "Tizen.NUI.Binding.StyleClass.";
 
+               const int CleanupTrigger = 128;
+               int cleanupThreshold = CleanupTrigger;
+
         readonly BindableProperty basedOnResourceProperty = BindableProperty.CreateAttached("BasedOnResource", typeof(XamlStyle), typeof(XamlStyle), default(XamlStyle),
             propertyChanged: OnBasedOnResourceChanged);
 
@@ -106,6 +110,7 @@ namespace Tizen.NUI.Binding
             if (BaseResourceKey != null)
                 bindable.SetDynamicResource(basedOnResourceProperty, BaseResourceKey);
             ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
+            CleanUpWeakReferences();
         }
 
         [EditorBrowsable(EditorBrowsableState.Never)]
@@ -168,11 +173,11 @@ namespace Tizen.NUI.Binding
 
         static void OnBasedOnResourceChanged(BindableObject bindable, object oldValue, object newValue)
         {
-            // Style style = (bindable as BaseHandle).Style;
-            // if (style == null)
-            //         return;
-            // style.UnApplyCore(bindable, (Style)oldValue);
-            // style.ApplyCore(bindable, (Style)newValue);
+            XamlStyle style = (bindable as View).XamlStyle;
+            if (style == null)
+                return;
+            style.UnApplyCore(bindable, (XamlStyle)oldValue);
+            style.ApplyCore(bindable, (XamlStyle)newValue);
         }
 
         void UnApplyCore(BindableObject bindable, XamlStyle basedOn)
@@ -192,5 +197,16 @@ namespace Tizen.NUI.Binding
                 return true;
             return value.TargetType.IsAssignableFrom(TargetType);
         }
-    }
+
+               void CleanUpWeakReferences()
+               {
+                       if (targets.Count < cleanupThreshold)
+                       {
+                               return;
+                       }
+
+                       targets.RemoveAll(t => !t.TryGetTarget(out _));
+                       cleanupThreshold = targets.Count + CleanupTrigger;
+               }
+       }
 }