2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 using System.Collections.Generic;
20 using System.ComponentModel;
22 using Tizen.NUI.BaseComponents;
23 using Tizen.NUI.Binding;
24 using Tizen.NUI.Binding.Internals;
29 /// The Container is an abstract class to be inherited from by classes that desire to have views
32 /// <since_tizen> 4 </since_tizen>
33 public abstract class Container : Animatable, IResourcesProvider
35 /// <summary> XamlStyleProperty </summary>
36 [EditorBrowsable(EditorBrowsableState.Never)]
37 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);
39 internal BaseHandle InternalParent;
40 private List<View> childViews = new List<View>();
41 private MergedStyle mergedStyle = null;
42 ResourceDictionary _resources;
43 bool IResourcesProvider.IsResourcesCreated => _resources != null;
45 static internal new void Preload()
49 // Do nothing. Just call for load static values.
50 var temporalXamlStyleProperty = XamlStyleProperty;
53 internal Container(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
55 // No un-managed data hence no need to store a native ptr
58 internal Container(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
60 // No un-managed data hence no need to store a native ptr
63 /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
64 [EditorBrowsable(EditorBrowsableState.Never)]
65 public ResourceDictionary XamlResources
69 if (_resources != null)
71 _resources = new ResourceDictionary();
72 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
77 if (_resources == value)
80 if (_resources != null)
81 ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
83 OnResourcesChanged(value);
84 if (_resources != null)
85 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
90 [EditorBrowsable(EditorBrowsableState.Never)]
91 public XamlStyle XamlStyle
95 return (XamlStyle)GetValue(XamlStyleProperty);
99 SetValue(XamlStyleProperty, value);
103 internal MergedStyle MergedStyle
107 if (null == mergedStyle)
109 mergedStyle = new MergedStyle(GetType(), this);
117 /// List of children of Container.
119 /// <since_tizen> 4 </since_tizen>
120 public List<View> Children
129 /// Gets the parent container.
132 /// <pre>The child container has been initialized.</pre>
133 /// <returns>The parent container.</returns>
134 /// <since_tizen> 4 </since_tizen>
135 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
136 public new Container Parent
145 /// Gets the number of children for this container.
148 /// <pre>The container has been initialized.</pre>
149 /// <returns>The number of children.</returns>
150 /// <since_tizen> 4 </since_tizen>
151 public uint ChildCount
155 return Convert.ToUInt32(Children.Count);
160 /// Copy all properties, bindings.
161 /// Copy children without xName from other container, copy all properties, bindings of children with xName.
163 /// <param name="other"></param>
164 [EditorBrowsable(EditorBrowsableState.Never)]
165 public void CopyAndKeepXNameInstance(Container other)
169 var nameScopeOfOther = NameScope.GetNameScope(other) as NameScope;
170 var nameScope = NameScope.GetNameScope(this) as NameScope;
172 if (null == nameScopeOfOther)
174 if (null != nameScope)
179 else if (!nameScopeOfOther.Equal(nameScope))
184 var xNameToElementsOfOther = nameScopeOfOther?.NameToElement;
185 var xNameToElements = nameScope?.NameToElement;
187 if (null != xNameToElements)
189 foreach (var pair in xNameToElements)
191 if (pair.Value is View view)
193 view.Parent?.Remove(view);
198 for (int i = Children.Count - 1; i >= 0; i--)
200 var child = GetChildAt((uint)i);
203 child.DisposeIncludeChildren();
208 if (null != xNameToElementsOfOther)
210 foreach (var pair in xNameToElementsOfOther)
212 if (pair.Value is View view)
214 var parent = view.Parent;
218 if ((null != xNameToElements) && (xNameToElements[pair.Key] is View holdedXElements))
220 holdedXElements.CopyBindingRelationShip(view);
221 holdedXElements.CopyFrom(view);
223 parent.ReplaceChild(view, holdedXElements);
230 ReplaceBindingElementInWholeTree(xNameToElementsOfOther, xNameToElements);
232 if (null != xNameToElementsOfOther)
234 foreach (var pair in xNameToElementsOfOther)
236 if (pair.Value is View view)
245 /// Dispose itself and all children recursively.
246 /// We can call this even itself is disposed.
249 /// Note that Container.DisposeIncludeChildren() disposed only if it created by xaml.
252 /// This is a hidden API(inhouse API) only for internal purpose.
254 [EditorBrowsable(EditorBrowsableState.Never)]
255 public void DisposeRecursively()
257 // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
258 if (!Disposed && !IsDisposeQueued)
263 // Copy child referecen to avoid Children changed during DisposeRecursively();
264 var copiedChildren = childViews.ToList();
266 // Make sure that itself don't have children anymore.
269 foreach (View child in copiedChildren)
271 if (!(child?.Disposed ?? true))
273 child.DisposeRecursively();
279 /// Adds a child view to this Container.
281 /// <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>
282 /// <post>The child will be referenced by its parent. This means that the child will be kept alive, even if the handle passed into this method is reset or destroyed.</post>
283 /// <remarks>If the child already has a parent, it will be removed from the old parent and reparented to this view. This may change child's position, color, scale, etc. as it now inherits them from this view.</remarks>
284 /// <param name="view">The child view to add.</param>
285 /// <since_tizen> 4 </since_tizen>
286 public abstract void Add(View view);
289 /// Removes a child view from this view. If the view was not a child of this view, this is a no-op.
291 /// <pre>This View(the parent) has been initialized. The child view is not the same as the parent view.</pre>
292 /// <param name="view">The view to remove</param>
293 /// <since_tizen> 4 </since_tizen>
294 public abstract void Remove(View view);
297 /// Retrieves the child view by the index.
299 /// <pre>The view has been initialized.</pre>
300 /// <param name="index">The index of the child to retrieve.</param>
301 /// <returns>The view for the given index or empty handle if children are not initialized.</returns>
302 /// <since_tizen> 4 </since_tizen>
303 public abstract View GetChildAt(uint index);
306 /// Gets the parent of this container.
308 /// <pre>The child container has been initialized.</pre>
309 /// <returns>The parent container.</returns>
310 /// <since_tizen> 4 </since_tizen>
311 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
312 public abstract Container GetParent();
315 /// Gets the number of children for this container.
317 /// <pre>The container has been initialized.</pre>
318 /// <returns>The number of children.</returns>
319 /// <since_tizen> 4 </since_tizen>
320 [Obsolete("This has been deprecated in API9 and will be removed in API11. Use ChildCount property instead.")]
321 public abstract UInt32 GetChildCount();
323 internal abstract View FindCurrentChildById(uint id);
325 internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
330 if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
332 base.OnParentResourcesChanged(values);
336 var innerKeys = new HashSet<string>();
337 var changedResources = new List<KeyValuePair<string, object>>();
338 foreach (KeyValuePair<string, object> c in XamlResources)
339 innerKeys.Add(c.Key);
340 foreach (KeyValuePair<string, object> value in values)
342 if (innerKeys.Add(value.Key))
343 changedResources.Add(value);
345 if (changedResources.Count != 0)
346 OnResourcesChanged(changedResources);
350 /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
352 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
353 [EditorBrowsable(EditorBrowsableState.Never)]
354 protected override void OnBindingContextChanged()
356 var gotBindingContext = false;
359 for (var index = 0; index < Children.Count; index++)
361 Element child = Children[index];
363 if (!gotBindingContext)
366 gotBindingContext = true;
369 SetChildInheritedBindingContext(child, bc);
371 base.OnBindingContextChanged();
374 private void DisposeIncludeChildren()
376 foreach (var child in Children)
378 child.DisposeIncludeChildren();
388 private void CopyChildren(Container other)
390 var childrenOfOtherView = new List<View>();
392 foreach (var child in other.Children)
394 childrenOfOtherView.Add(child);
397 foreach (var child in childrenOfOtherView)
403 private void ReplaceChild(View child, View newChild)
405 int indexOfView = Children.FindIndex((View v) => { return v == child; });
407 var childrenNeedtoReAdd = new Stack<View>();
409 for (int i = Children.Count - 1; i > indexOfView; i--)
411 childrenNeedtoReAdd.Push(Children[i]);
417 childrenNeedtoReAdd.Push(newChild);
419 while (0 < childrenNeedtoReAdd.Count)
421 Add(childrenNeedtoReAdd.Pop());
425 private void ReplaceBindingElementInWholeTree(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
429 ReplaceBindingElement(oldNameScope, newNameScope);
431 foreach (var child in Children)
433 child.ReplaceBindingElementInWholeTree(oldNameScope, newNameScope);
438 } // namespace Tizen.NUI