From 032976d6859a27ac4962ccc53d40da27d9ced9bf Mon Sep 17 00:00:00 2001 From: Xianbing Teng Date: Thu, 17 Feb 2022 18:03:47 +0800 Subject: [PATCH] [NUI]Fix ResourcesDictionary & BindingContext issues 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. --- .../src/internal/Application/Application.cs | 11 +- .../src/internal/Xaml/ApplyPropertiesVisitor.cs | 40 ++++--- .../src/internal/Xaml/CreateValuesVisitor.cs | 17 +-- .../Xaml/FillResourceDictionariesVisitor.cs | 17 +-- .../src/internal/Xaml/IResourcesLoader.cs | 6 +- src/Tizen.NUI/src/internal/Xaml/ResourcesLoader.cs | 24 +++-- src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs | 10 +- .../XamlBinding/Internals/ResourceLoader.cs | 40 ++++--- .../src/internal/XamlBinding/MergedStyle.cs | 11 +- .../internal/XamlBinding/ResourcesExtensions.cs | 11 +- src/Tizen.NUI/src/public/BaseComponents/View.cs | 39 +------ .../public/BaseComponents/ViewBindableProperty.cs | 6 -- .../src/public/BaseComponents/ViewInternal.cs | 24 +---- .../src/public/BaseComponents/ViewPublicMethods.cs | 7 +- src/Tizen.NUI/src/public/Common/BaseHandle.cs | 7 +- src/Tizen.NUI/src/public/Common/Container.cs | 115 ++++++++++++++++++++- src/Tizen.NUI/src/public/Common/Layer.cs | 18 +--- .../src/public/Xaml/XamlFilePathAttribute.cs | 15 +-- .../src/public/Xaml/XamlParseException.cs | 11 +- .../src/public/XamlBinding/BindableObject.cs | 75 +++----------- src/Tizen.NUI/src/public/XamlBinding/Element.cs | 12 +-- .../src/public/XamlBinding/IValueConverter.cs | 2 +- .../src/public/XamlBinding/ResourceDictionary.cs | 4 +- src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs | 28 +++-- 24 files changed, 297 insertions(+), 253 deletions(-) mode change 100644 => 100755 src/Tizen.NUI/src/public/Common/BaseHandle.cs diff --git a/src/Tizen.NUI/src/internal/Application/Application.cs b/src/Tizen.NUI/src/internal/Application/Application.cs index ac87ddc..73430e0 100755 --- a/src/Tizen.NUI/src/internal/Application/Application.cs +++ b/src/Tizen.NUI/src/internal/Application/Application.cs @@ -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 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> 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) diff --git a/src/Tizen.NUI/src/internal/Xaml/ApplyPropertiesVisitor.cs b/src/Tizen.NUI/src/internal/Xaml/ApplyPropertiesVisitor.cs index 0ca6d91..e1af6ff 100755 --- a/src/Tizen.NUI/src/internal/Xaml/ApplyPropertiesVisitor.cs +++ b/src/Tizen.NUI/src/internal/Xaml/ApplyPropertiesVisitor.cs @@ -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 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 diff --git a/src/Tizen.NUI/src/internal/Xaml/CreateValuesVisitor.cs b/src/Tizen.NUI/src/internal/Xaml/CreateValuesVisitor.cs index d9f70ae..9336e8b 100755 --- a/src/Tizen.NUI/src/internal/Xaml/CreateValuesVisitor.cs +++ b/src/Tizen.NUI/src/internal/Xaml/CreateValuesVisitor.cs @@ -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; } } diff --git a/src/Tizen.NUI/src/internal/Xaml/FillResourceDictionariesVisitor.cs b/src/Tizen.NUI/src/internal/Xaml/FillResourceDictionariesVisitor.cs index 2b8abe8..eeae4f2 100755 --- a/src/Tizen.NUI/src/internal/Xaml/FillResourceDictionariesVisitor.cs +++ b/src/Tizen.NUI/src/internal/Xaml/FillResourceDictionariesVisitor.cs @@ -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 diff --git a/src/Tizen.NUI/src/internal/Xaml/IResourcesLoader.cs b/src/Tizen.NUI/src/internal/Xaml/IResourcesLoader.cs index 8ea6349..732f23d 100755 --- a/src/Tizen.NUI/src/internal/Xaml/IResourcesLoader.cs +++ b/src/Tizen.NUI/src/internal/Xaml/IResourcesLoader.cs @@ -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(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); } } diff --git a/src/Tizen.NUI/src/internal/Xaml/ResourcesLoader.cs b/src/Tizen.NUI/src/internal/Xaml/ResourcesLoader.cs index 14cd470..433743f 100755 --- a/src/Tizen.NUI/src/internal/Xaml/ResourcesLoader.cs +++ b/src/Tizen.NUI/src/internal/Xaml/ResourcesLoader.cs @@ -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(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; diff --git a/src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs b/src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs index 37078b6..b999ccb 100755 --- a/src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs +++ b/src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs @@ -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)null) + ExceptionHandler = doNotThrow ? ehandler : (Action)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)null) + ExceptionHandler = doNotThrow ? ehandler : (Action)null #pragma warning restore 0618 }); break; diff --git a/src/Tizen.NUI/src/internal/XamlBinding/Internals/ResourceLoader.cs b/src/Tizen.NUI/src/internal/XamlBinding/Internals/ResourceLoader.cs index 7c20e06..3910c7e 100755 --- a/src/Tizen.NUI/src/internal/XamlBinding/Internals/ResourceLoader.cs +++ b/src/Tizen.NUI/src/internal/XamlBinding/Internals/ResourceLoader.cs @@ -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 resourceProvider = (asmName, path) => - { - if (typeof(Theme).Assembly.GetName().FullName != asmName.FullName) + static Func _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 ResourceProvider + public static Func ResourceProvider { - get => resourceProvider; + get => _resourceProvider; internal set { - DesignMode.IsDesignModeEnabled = true; - resourceProvider = value; + DesignMode.IsDesignModeEnabled = value != null; + _resourceProvider = value; } } - internal static Action 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; } + } } } diff --git a/src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs b/src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs index ebf6439..22572f1 100755 --- a/src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs +++ b/src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs @@ -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 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); diff --git a/src/Tizen.NUI/src/internal/XamlBinding/ResourcesExtensions.cs b/src/Tizen.NUI/src/internal/XamlBinding/ResourcesExtensions.cs index b0ccc27..ad6e6ea 100755 --- a/src/Tizen.NUI/src/internal/XamlBinding/ResourcesExtensions.cs +++ b/src/Tizen.NUI/src/internal/XamlBinding/ResourcesExtensions.cs @@ -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 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); + } } } diff --git a/src/Tizen.NUI/src/public/BaseComponents/View.cs b/src/Tizen.NUI/src/public/BaseComponents/View.cs index f00d363..151e709 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/View.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/View.cs @@ -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; - } - } - /// /// 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); - } - } - /// /// The Color of View. This is an RGBA value. /// diff --git a/src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs b/src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs index 755a331..ffb81e4 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs @@ -1705,12 +1705,6 @@ namespace Tizen.NUI.BaseComponents }); /// - /// XamlStyleProperty - /// - [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); - - /// /// EnableControlState property /// [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs b/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs index fa912ef..4fb9504 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs @@ -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. @@ -16,11 +16,7 @@ */ 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 /// 3 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 diff --git a/src/Tizen.NUI/src/public/BaseComponents/ViewPublicMethods.cs b/src/Tizen.NUI/src/public/BaseComponents/ViewPublicMethods.cs index 1d7dac3..84bc781 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ViewPublicMethods.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ViewPublicMethods.cs @@ -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); } } diff --git a/src/Tizen.NUI/src/public/Common/BaseHandle.cs b/src/Tizen.NUI/src/public/Common/BaseHandle.cs old mode 100644 new mode 100755 index 0b594fe..909138a --- a/src/Tizen.NUI/src/public/Common/BaseHandle.cs +++ b/src/Tizen.NUI/src/public/Common/BaseHandle.cs @@ -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; - } } /// diff --git a/src/Tizen.NUI/src/public/Common/Container.cs b/src/Tizen.NUI/src/public/Common/Container.cs index 799251c..90444ab 100755 --- a/src/Tizen.NUI/src/public/Common/Container.cs +++ b/src/Tizen.NUI/src/public/Common/Container.cs @@ -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. /// /// 4 - public abstract class Container : Animatable + public abstract class Container : Animatable, IResourcesProvider { + /// XamlStyleProperty + [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 childViews = new List(); + 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; + } + } + /// /// List of children of Container. /// @@ -125,5 +187,54 @@ namespace Tizen.NUI public abstract UInt32 GetChildCount(); internal abstract View FindCurrentChildById(uint id); + + internal override void OnParentResourcesChanged(IEnumerable> values) + { + if (values == null) + return; + + if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0) + { + base.OnParentResourcesChanged(values); + return; + } + + var innerKeys = new HashSet(); + var changedResources = new List>(); + foreach (KeyValuePair c in XamlResources) + innerKeys.Add(c.Key); + foreach (KeyValuePair value in values) + { + if (innerKeys.Add(value.Key)) + changedResources.Add(value); + } + if (changedResources.Count != 0) + OnResourcesChanged(changedResources); + } + + /// + /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event. + /// + /// 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 diff --git a/src/Tizen.NUI/src/public/Common/Layer.cs b/src/Tizen.NUI/src/public/Common/Layer.cs index 494286b..6f18d36 100755 --- a/src/Tizen.NUI/src/public/Common/Layer.cs +++ b/src/Tizen.NUI/src/public/Common/Layer.cs @@ -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; - } - } - /// /// 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); } /// diff --git a/src/Tizen.NUI/src/public/Xaml/XamlFilePathAttribute.cs b/src/Tizen.NUI/src/public/Xaml/XamlFilePathAttribute.cs index 3e90165..dcbe7c8 100755 --- a/src/Tizen.NUI/src/public/Xaml/XamlFilePathAttribute.cs +++ b/src/Tizen.NUI/src/public/Xaml/XamlFilePathAttribute.cs @@ -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; } } diff --git a/src/Tizen.NUI/src/public/Xaml/XamlParseException.cs b/src/Tizen.NUI/src/public/Xaml/XamlParseException.cs index da1c3f5..168bbba 100755 --- a/src/Tizen.NUI/src/public/Xaml/XamlParseException.cs +++ b/src/Tizen.NUI/src/public/Xaml/XamlParseException.cs @@ -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(); } } diff --git a/src/Tizen.NUI/src/public/XamlBinding/BindableObject.cs b/src/Tizen.NUI/src/public/XamlBinding/BindableObject.cs index 7fe28e9..cfed29f 100755 --- a/src/Tizen.NUI/src/public/XamlBinding/BindableObject.cs +++ b/src/Tizen.NUI/src/public/XamlBinding/BindableObject.cs @@ -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 /// [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 properties = new List(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 children = new List(); - - private void FlushBinding() - { - ApplyBindings(skipBindingContext: true, fromBindingContextChanged: true); - OnBindingContextChanged(); - - foreach (var child in children) - { - child.FlushBinding(); - } - } } } diff --git a/src/Tizen.NUI/src/public/XamlBinding/Element.cs b/src/Tizen.NUI/src/public/XamlBinding/Element.cs index 18a0ea0..79f4f7f 100755 --- a/src/Tizen.NUI/src/public/XamlBinding/Element.cs +++ b/src/Tizen.NUI/src/public/XamlBinding/Element.cs @@ -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> 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; diff --git a/src/Tizen.NUI/src/public/XamlBinding/IValueConverter.cs b/src/Tizen.NUI/src/public/XamlBinding/IValueConverter.cs index 1ee2a5d..937ff82 100755 --- a/src/Tizen.NUI/src/public/XamlBinding/IValueConverter.cs +++ b/src/Tizen.NUI/src/public/XamlBinding/IValueConverter.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright(c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/Tizen.NUI/src/public/XamlBinding/ResourceDictionary.cs b/src/Tizen.NUI/src/public/XamlBinding/ResourceDictionary.cs index 797436b..1051090 100755 --- a/src/Tizen.NUI/src/public/XamlBinding/ResourceDictionary.cs +++ b/src/Tizen.NUI/src/public/XamlBinding/ResourceDictionary.cs @@ -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 diff --git a/src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs b/src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs index 64edce2..f1a9d74 100755 --- a/src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs +++ b/src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs @@ -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; + } + } } -- 2.7.4