/*
- * 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 Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
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>
}
/// <summary>
+ /// Copy all properties, bindings.
+ /// Copy children without xName from other container, copy all properties, bindings of children with xName.
+ /// </summary>
+ /// <param name="other"></param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void CopyAndKeepXNameInstance(Container other)
+ {
+ CopyFrom(other);
+
+ var nameScopeOfOther = NameScope.GetNameScope(other) as NameScope;
+ var nameScope = NameScope.GetNameScope(this) as NameScope;
+
+ if (null == nameScopeOfOther)
+ {
+ if (null != nameScope)
+ {
+ return;
+ }
+ }
+ else if (!nameScopeOfOther.Equal(nameScope))
+ {
+ return;
+ }
+
+ var xNameToElementsOfOther = nameScopeOfOther?.NameToElement;
+ var xNameToElements = nameScope?.NameToElement;
+
+ if (null != xNameToElements)
+ {
+ foreach (var pair in xNameToElements)
+ {
+ if (pair.Value is View view)
+ {
+ view.Parent?.Remove(view);
+ }
+ }
+ }
+
+ for (int i = Children.Count - 1; i >= 0; i--)
+ {
+ var child = GetChildAt((uint)i);
+ Remove(child);
+
+ child.DisposeIncludeChildren();
+ }
+
+ CopyChildren(other);
+
+ if (null != xNameToElementsOfOther)
+ {
+ foreach (var pair in xNameToElementsOfOther)
+ {
+ if (pair.Value is View view)
+ {
+ var parent = view.Parent;
+
+ if (null != parent)
+ {
+ if ((null != xNameToElements) && (xNameToElements[pair.Key] is View holdedXElements))
+ {
+ holdedXElements.CopyBindingRelationShip(view);
+ holdedXElements.CopyFrom(view);
+
+ parent.ReplaceChild(view, holdedXElements);
+ }
+ }
+ }
+ }
+ }
+
+ ReplaceBindingElementInWholeTree(xNameToElementsOfOther, xNameToElements);
+
+ if (null != xNameToElementsOfOther)
+ {
+ foreach (var pair in xNameToElementsOfOther)
+ {
+ if (pair.Value is View view)
+ {
+ view.Dispose();
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Dispose itself and all children recursively.
+ /// We can call this even itself is disposed.
+ /// </summary>
+ /// <remarks>
+ /// Note that Container.DisposeIncludeChildren() disposed only if it created by xaml.
+ /// </remarks>
+ /// <remarks>
+ /// This is a hidden API(inhouse API) only for internal purpose.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void DisposeRecursively()
+ {
+ // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
+ if(!Disposed && !IsDisposeQueued)
+ {
+ Dispose();
+ }
+
+ foreach (View child in Children)
+ {
+ child.DisposeRecursively();
+ }
+
+ // Make sure that itself don't have children anymore.
+ childViews?.Clear();
+ }
+
+ /// <summary>
/// Adds a child view to this Container.
/// </summary>
/// <pre>This Container (the parent) has been initialized. The child view has been initialized. The child view is not the same as the parent view.</pre>
/// <pre>The container has been initialized.</pre>
/// <returns>The number of children.</returns>
/// <since_tizen> 4 </since_tizen>
- [Obsolete("Deprecated in API9, will be removed in API11. Please use ChildCount property instead!")]
+ [Obsolete("This has been deprecated in API9 and will be removed in API11. Use ChildCount property instead.")]
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();
+ }
+
+ private void DisposeIncludeChildren()
+ {
+ foreach (var child in Children)
+ {
+ child.DisposeIncludeChildren();
+ }
+
+ if (IsCreateByXaml)
+ {
+ Dispose();
+ ClearBinding();
+ }
+ }
+
+ private void CopyChildren(Container other)
+ {
+ var childrenOfOtherView = new List<View>();
+
+ foreach (var child in other.Children)
+ {
+ childrenOfOtherView.Add(child);
+ }
+
+ foreach (var child in childrenOfOtherView)
+ {
+ Add(child);
+ }
+ }
+
+ private void ReplaceChild(View child, View newChild)
+ {
+ int indexOfView = Children.FindIndex((View v) => { return v == child; });
+
+ var childrenNeedtoReAdd = new Stack<View>();
+
+ for (int i = Children.Count - 1; i > indexOfView; i--)
+ {
+ childrenNeedtoReAdd.Push(Children[i]);
+ Remove(Children[i]);
+ }
+
+ Remove(child);
+
+ childrenNeedtoReAdd.Push(newChild);
+
+ while (0 < childrenNeedtoReAdd.Count)
+ {
+ Add(childrenNeedtoReAdd.Pop());
+ }
+ }
+
+ private void ReplaceBindingElementInWholeTree(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
+ {
+ if (IsCreateByXaml)
+ {
+ ReplaceBindingElement(oldNameScope, newNameScope);
+
+ foreach (var child in Children)
+ {
+ child.ReplaceBindingElementInWholeTree(oldNameScope, newNameScope);
+ }
+ }
+ }
}
} // namespace Tizen.NUI