[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>
Fri, 4 Mar 2022 05:31:52 +0000 (14:31 +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 499f12d..97462a7 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;
                             element.LineNumber = node.LineNumber;
                             element.LinePosition = node.LinePosition;
@@ -288,11 +283,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;
                     element.LineNumber = (node as ElementNode)?.LineNumber ?? -1;
                     element.LinePosition = (node as ElementNode)?.LinePosition ?? -1;
@@ -430,11 +420,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;
                     element.LineNumber = (node as ElementNode)?.LineNumber ?? -1;
                     element.LinePosition = (node as ElementNode)?.LinePosition ?? -1;
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 e3b803e..55edd7d 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.
@@ -130,11 +130,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;
@@ -178,11 +180,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 4c6d186..185f04f 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.
@@ -289,30 +289,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.
@@ -2638,19 +2614,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 51ff3ec..3cfc50c 100755 (executable)
@@ -1888,12 +1888,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 212cea8..6fc6bd6 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();
@@ -1038,8 +1021,7 @@ namespace Tizen.NUI.BaseComponents
             child.InternalParent = null;
             LayoutCount -= child.LayoutCount;
 
-            RemoveChildBindableObject(child);
-
+            OnChildRemoved(child);
             if (ChildRemoved != null)
             {
                 ChildRemovedEventArgs e = new ChildRemovedEventArgs
index 489c7c0..f78edcb 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.
@@ -158,6 +158,7 @@ namespace Tizen.NUI.BaseComponents
                 if (NDalicPINVOKE.SWIGPendingException.Pending)
                     throw NDalicPINVOKE.SWIGPendingException.Retrieve();
                 Children.Add(child);
+                OnChildAdded(child);
 
                 if (ChildAdded != null)
                 {
@@ -167,8 +168,6 @@ namespace Tizen.NUI.BaseComponents
                     };
                     ChildAdded(this, e);
                 }
-
-                AddChildBindableObject(child);
             }
         }
 
old mode 100644 (file)
new mode 100755 (executable)
index c033810..b50fd7f
@@ -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.
@@ -608,11 +608,6 @@ namespace Tizen.NUI
             }
 
             disposed = true;
-
-            if (null != Application.Current)
-            {
-                Application.Current.XamlResourceChanged -= OnResourcesChanged;
-            }
             DebugFileLogging.Instance.WriteLog($"BaseHandle.Dispose({type}) END");
             DebugFileLogging.Instance.WriteLog($"=============================");
             NUILog.Debug($"BaseHandle.Dispose({type}) END");
index 6652914..9174575 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.
@@ -19,6 +19,7 @@ using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
 using Tizen.NUI.Binding.Internals;
 
 namespace Tizen.NUI
@@ -28,16 +29,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>
@@ -214,6 +275,55 @@ namespace Tizen.NUI
 
         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();
+        }
+
         private void DisposeIncludeChildren()
         {
             foreach (var child in Children)
index 6e52bf2..a78c3cd 100755 (executable)
@@ -17,7 +17,6 @@
 using System;
 using Tizen.NUI.BaseComponents;
 using System.ComponentModel;
-using Tizen.NUI.Binding;
 
 namespace Tizen.NUI
 {
@@ -28,7 +27,6 @@ namespace Tizen.NUI
     public class Layer : Container
     {
         private Window window;
-
         private int layoutCount = 0;
 
         /// <summary>
@@ -260,20 +258,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
@@ -324,7 +308,7 @@ namespace Tizen.NUI
                 if (NDalicPINVOKE.SWIGPendingException.Pending)
                     throw NDalicPINVOKE.SWIGPendingException.Retrieve();
                 Children.Add(child);
-                BindableObject.SetInheritedBindingContext(child, this?.BindingContext);
+                OnChildAdded(child);
             }
         }
 
@@ -356,7 +340,7 @@ namespace Tizen.NUI
 
             Children.Remove(child);
             child.InternalParent = null;
-
+            OnChildRemoved(child);
             LayoutCount -= child.LayoutCount;
         }
 
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 97d99a2..9bac951 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.
@@ -37,36 +37,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 Dictionary<BindableProperty, BindablePropertyContext> properties = new Dictionary<BindableProperty, BindablePropertyContext>(4);
 
@@ -814,6 +786,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;
@@ -1095,20 +1079,6 @@ namespace Tizen.NUI.Binding
             }
         }
 
-        internal void AddChildBindableObject(BindableObject child)
-        {
-            if (null != child)
-            {
-                children.Add(child);
-                child.FlushBinding();
-            }
-        }
-
-        internal void RemoveChildBindableObject(BindableObject child)
-        {
-            children.Remove(child);
-        }
-
         internal void ReplaceBindingElement(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
         {
             var xElementToNameOfOld = new Dictionary<object, string>();
@@ -1158,19 +1128,6 @@ namespace Tizen.NUI.Binding
                 }
             }
         }
-
-        private List<BindableObject> children = new List<BindableObject>();
-
-        private void FlushBinding()
-        {
-            ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true);
-            OnBindingContextChanged();
-
-            foreach (var child in children)
-            {
-                child.FlushBinding();
-            }
-        }
     }
 }
 
index 21271a4..e92b21e 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.
@@ -448,10 +448,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)
@@ -520,11 +517,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;
+               }
+       }
 }