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;
21 using Tizen.NUI.BaseComponents;
22 using Tizen.NUI.Binding;
23 using Tizen.NUI.Binding.Internals;
28 /// The Container is an abstract class to be inherited from by classes that desire to have views
31 /// <since_tizen> 4 </since_tizen>
32 public abstract class Container : Animatable, IResourcesProvider
34 /// <summary> XamlStyleProperty </summary>
35 [EditorBrowsable(EditorBrowsableState.Never)]
36 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);
38 internal BaseHandle InternalParent;
39 private List<View> childViews = new List<View>();
40 private MergedStyle mergedStyle = null;
41 ResourceDictionary _resources;
42 bool IResourcesProvider.IsResourcesCreated => _resources != null;
44 internal Container(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
46 // No un-managed data hence no need to store a native ptr
49 /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
50 [EditorBrowsable(EditorBrowsableState.Never)]
51 public ResourceDictionary XamlResources
55 if (_resources != null)
57 _resources = new ResourceDictionary();
58 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
63 if (_resources == value)
66 if (_resources != null)
67 ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
69 OnResourcesChanged(value);
70 if (_resources != null)
71 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
76 [EditorBrowsable(EditorBrowsableState.Never)]
77 public XamlStyle XamlStyle
81 return (XamlStyle)GetValue(XamlStyleProperty);
85 SetValue(XamlStyleProperty, value);
89 internal MergedStyle MergedStyle
93 if (null == mergedStyle)
95 mergedStyle = new MergedStyle(GetType(), this);
103 /// List of children of Container.
105 /// <since_tizen> 4 </since_tizen>
106 public List<View> Children
110 return GetChildren();
115 /// Gets the parent container.
118 /// <pre>The child container has been initialized.</pre>
119 /// <returns>The parent container.</returns>
120 /// <since_tizen> 4 </since_tizen>
121 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
122 public new Container Parent
131 /// Gets the number of children for this container.
134 /// <pre>The container has been initialized.</pre>
135 /// <returns>The number of children.</returns>
136 /// <since_tizen> 4 </since_tizen>
137 public uint ChildCount
141 return Convert.ToUInt32(Children.Count);
146 /// Copy all properties, bindings.
147 /// Copy children without xName from other container, copy all properties, bindings of children with xName.
149 /// <param name="other"></param>
150 [EditorBrowsable(EditorBrowsableState.Never)]
151 public void CopyAndKeepXNameInstance(Container other)
155 var nameScopeOfOther = NameScope.GetNameScope(other) as NameScope;
156 var nameScope = NameScope.GetNameScope(this) as NameScope;
158 if (null == nameScopeOfOther)
160 if (null != nameScope)
165 else if (!nameScopeOfOther.Equal(nameScope))
170 var xNameToElementsOfOther = nameScopeOfOther?.NameToElement;
171 var xNameToElements = nameScope?.NameToElement;
173 if (null != xNameToElements)
175 foreach (var pair in xNameToElements)
177 if (pair.Value is View view)
179 view.Parent?.Remove(view);
184 for (int i = Children.Count - 1; i >= 0; i--)
186 var child = GetChildAt((uint)i);
189 child.DisposeIncludeChildren();
194 if (null != xNameToElementsOfOther)
196 foreach (var pair in xNameToElementsOfOther)
198 if (pair.Value is View view)
200 var parent = view.Parent;
204 if ((null != xNameToElements) && (xNameToElements[pair.Key] is View holdedXElements))
206 holdedXElements.CopyBindingRelationShip(view);
207 holdedXElements.CopyFrom(view);
209 parent.ReplaceChild(view, holdedXElements);
216 ReplaceBindingElementInWholeTree(xNameToElementsOfOther, xNameToElements);
218 if (null != xNameToElementsOfOther)
220 foreach (var pair in xNameToElementsOfOther)
222 if (pair.Value is View view)
231 /// Dispose itself and all children recursively.
232 /// We can call this even itself is disposed.
235 /// Note that Container.DisposeIncludeChildren() disposed only if it created by xaml.
238 /// This is a hidden API(inhouse API) only for internal purpose.
240 [EditorBrowsable(EditorBrowsableState.Never)]
241 public void DisposeRecursively()
243 // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
244 if(!Disposed && !IsDisposeQueued)
249 foreach (View child in Children)
251 child.DisposeRecursively();
254 // Make sure that itself don't have children anymore.
259 /// Adds a child view to this Container.
261 /// <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>
262 /// <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>
263 /// <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>
264 /// <param name="view">The child view to add.</param>
265 /// <since_tizen> 4 </since_tizen>
266 public abstract void Add(View view);
269 /// Removes a child view from this view. If the view was not a child of this view, this is a no-op.
271 /// <pre>This View(the parent) has been initialized. The child view is not the same as the parent view.</pre>
272 /// <param name="view">The view to remove</param>
273 /// <since_tizen> 4 </since_tizen>
274 public abstract void Remove(View view);
277 /// Retrieves the child view by the index.
279 /// <pre>The view has been initialized.</pre>
280 /// <param name="index">The index of the child to retrieve.</param>
281 /// <returns>The view for the given index or empty handle if children are not initialized.</returns>
282 /// <since_tizen> 4 </since_tizen>
283 public abstract View GetChildAt(uint index);
286 /// Gets the parent of this container.
288 /// <pre>The child container has been initialized.</pre>
289 /// <returns>The parent container.</returns>
290 /// <since_tizen> 4 </since_tizen>
291 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
292 public abstract Container GetParent();
295 /// Gets the number of children for this container.
297 /// <pre>The container has been initialized.</pre>
298 /// <returns>The number of children.</returns>
299 /// <since_tizen> 4 </since_tizen>
300 [Obsolete("This has been deprecated in API9 and will be removed in API11. Use ChildCount property instead.")]
301 public abstract UInt32 GetChildCount();
303 internal abstract View FindCurrentChildById(uint id);
305 internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
310 if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
312 base.OnParentResourcesChanged(values);
316 var innerKeys = new HashSet<string>();
317 var changedResources = new List<KeyValuePair<string, object>>();
318 foreach (KeyValuePair<string, object> c in XamlResources)
319 innerKeys.Add(c.Key);
320 foreach (KeyValuePair<string, object> value in values)
322 if (innerKeys.Add(value.Key))
323 changedResources.Add(value);
325 if (changedResources.Count != 0)
326 OnResourcesChanged(changedResources);
330 /// Some type which inherit from Container overwrite the Add/Remove, so the getter of children should also be overwrite.
332 /// <returns></returns>
333 [EditorBrowsable(EditorBrowsableState.Never)]
334 protected virtual List<View> GetChildren()
340 /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
342 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
343 [EditorBrowsable(EditorBrowsableState.Never)]
344 protected override void OnBindingContextChanged()
346 var gotBindingContext = false;
349 for (var index = 0; index < Children.Count; index++)
351 Element child = Children[index];
353 if (!gotBindingContext)
356 gotBindingContext = true;
359 SetChildInheritedBindingContext(child, bc);
361 base.OnBindingContextChanged();
364 private void DisposeIncludeChildren()
366 foreach (var child in Children)
368 child.DisposeIncludeChildren();
378 private void CopyChildren(Container other)
380 var childrenOfOtherView = new List<View>();
382 foreach (var child in other.Children)
384 childrenOfOtherView.Add(child);
387 foreach (var child in childrenOfOtherView)
393 private void ReplaceChild(View child, View newChild)
395 int indexOfView = Children.FindIndex((View v) => { return v == child; });
397 var childrenNeedtoReAdd = new Stack<View>();
399 for (int i = Children.Count - 1; i > indexOfView; i--)
401 childrenNeedtoReAdd.Push(Children[i]);
407 childrenNeedtoReAdd.Push(newChild);
409 while (0 < childrenNeedtoReAdd.Count)
411 Add(childrenNeedtoReAdd.Pop());
415 private void ReplaceBindingElementInWholeTree(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
419 ReplaceBindingElement(oldNameScope, newNameScope);
421 foreach (var child in Children)
423 child.ReplaceBindingElementInWholeTree(oldNameScope, newNameScope);
428 } // namespace Tizen.NUI