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 BindableProperty XamlStyleProperty = null;
38 internal static void SetInternalXamlStyleProperty(BindableObject bindable, object oldValue, object newValue)
40 ((View)bindable).MergedStyle.Style = (XamlStyle)newValue;
42 internal static object GetInternalXamlStyleProperty(BindableObject bindable)
44 return ((View)bindable).MergedStyle.Style;
47 internal BaseHandle InternalParent;
48 private List<View> childViews = new List<View>();
49 private MergedStyle mergedStyle = null;
50 ResourceDictionary _resources;
51 bool IResourcesProvider.IsResourcesCreated => _resources != null;
53 static internal new void Preload()
60 if (NUIApplication.IsUsingXaml)
62 XamlStyleProperty = BindableProperty.Create(nameof(XamlStyle), typeof(XamlStyle), typeof(Container), default(XamlStyle),
63 propertyChanged: SetInternalXamlStyleProperty, defaultValueCreator: GetInternalXamlStyleProperty);
67 internal Container(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
69 // No un-managed data hence no need to store a native ptr
72 internal Container(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
74 // No un-managed data hence no need to store a native ptr
77 /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
78 [EditorBrowsable(EditorBrowsableState.Never)]
79 public ResourceDictionary XamlResources
83 if (_resources != null)
85 _resources = new ResourceDictionary();
86 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
91 if (_resources == value)
94 if (_resources != null)
95 ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
97 OnResourcesChanged(value);
98 if (_resources != null)
99 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
104 [EditorBrowsable(EditorBrowsableState.Never)]
105 public XamlStyle XamlStyle
109 if (NUIApplication.IsUsingXaml)
111 return (XamlStyle)GetValue(XamlStyleProperty);
115 return (XamlStyle)GetInternalXamlStyleProperty(this);
120 if (NUIApplication.IsUsingXaml)
122 SetValue(XamlStyleProperty, value);
126 SetInternalXamlStyleProperty(this, null, value);
131 internal MergedStyle MergedStyle
135 if (null == mergedStyle)
137 mergedStyle = new MergedStyle(GetType(), this);
145 /// List of children of Container.
147 /// <since_tizen> 4 </since_tizen>
148 public List<View> Children
157 /// Gets the parent container.
160 /// <pre>The child container has been initialized.</pre>
161 /// <returns>The parent container.</returns>
162 /// <since_tizen> 4 </since_tizen>
163 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
164 public new Container Parent
173 /// Gets the number of children for this container.
176 /// <pre>The container has been initialized.</pre>
177 /// <returns>The number of children.</returns>
178 /// <since_tizen> 4 </since_tizen>
179 public uint ChildCount
183 return Convert.ToUInt32(Children.Count);
188 /// Copy all properties, bindings.
189 /// Copy children without xName from other container, copy all properties, bindings of children with xName.
191 /// <param name="other"></param>
192 [EditorBrowsable(EditorBrowsableState.Never)]
193 public void CopyAndKeepXNameInstance(Container other)
197 var nameScopeOfOther = NameScope.GetNameScope(other) as NameScope;
198 var nameScope = NameScope.GetNameScope(this) as NameScope;
200 if (null == nameScopeOfOther)
202 if (null != nameScope)
207 else if (!nameScopeOfOther.Equal(nameScope))
212 var xNameToElementsOfOther = nameScopeOfOther?.NameToElement;
213 var xNameToElements = nameScope?.NameToElement;
215 if (null != xNameToElements)
217 foreach (var pair in xNameToElements)
219 if (pair.Value is View view)
221 view.Parent?.Remove(view);
226 for (int i = Children.Count - 1; i >= 0; i--)
228 var child = GetChildAt((uint)i);
231 child.DisposeIncludeChildren();
236 if (null != xNameToElementsOfOther)
238 foreach (var pair in xNameToElementsOfOther)
240 if (pair.Value is View view)
242 var parent = view.Parent;
246 if ((null != xNameToElements) && (xNameToElements[pair.Key] is View holdedXElements))
248 holdedXElements.CopyBindingRelationShip(view);
249 holdedXElements.CopyFrom(view);
251 parent.ReplaceChild(view, holdedXElements);
258 ReplaceBindingElementInWholeTree(xNameToElementsOfOther, xNameToElements);
260 if (null != xNameToElementsOfOther)
262 foreach (var pair in xNameToElementsOfOther)
264 if (pair.Value is View view)
273 /// Dispose itself and all children recursively.
274 /// We can call this even itself is disposed.
277 /// Note that Container.DisposeIncludeChildren() disposed only if it created by xaml.
280 /// This is a hidden API(inhouse API) only for internal purpose.
282 [EditorBrowsable(EditorBrowsableState.Never)]
283 public void DisposeRecursively()
285 // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
286 if (!Disposed && !IsDisposeQueued)
291 // Copy child referecen to avoid Children changed during DisposeRecursively();
292 var copiedChildren = childViews.ToList();
294 // Make sure that itself don't have children anymore.
297 foreach (View child in copiedChildren)
299 if (!(child?.Disposed ?? true))
301 child.DisposeRecursively();
307 /// Adds a child view to this Container.
309 /// <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>
310 /// <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>
311 /// <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>
312 /// <param name="view">The child view to add.</param>
313 /// <since_tizen> 4 </since_tizen>
314 public abstract void Add(View view);
317 /// Removes a child view from this view. If the view was not a child of this view, this is a no-op.
319 /// <pre>This View(the parent) has been initialized. The child view is not the same as the parent view.</pre>
320 /// <param name="view">The view to remove</param>
321 /// <since_tizen> 4 </since_tizen>
322 public abstract void Remove(View view);
325 /// Retrieves the child view by the index.
327 /// <pre>The view has been initialized.</pre>
328 /// <param name="index">The index of the child to retrieve.</param>
329 /// <returns>The view for the given index or empty handle if children are not initialized.</returns>
330 /// <since_tizen> 4 </since_tizen>
331 public abstract View GetChildAt(uint index);
334 /// Gets the parent of this container.
336 /// <pre>The child container has been initialized.</pre>
337 /// <returns>The parent container.</returns>
338 /// <since_tizen> 4 </since_tizen>
339 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1721: Property names should not match get methods")]
340 public abstract Container GetParent();
343 /// Gets the number of children for this container.
345 /// <pre>The container has been initialized.</pre>
346 /// <returns>The number of children.</returns>
347 /// <since_tizen> 4 </since_tizen>
348 [Obsolete("This has been deprecated in API9 and will be removed in API11. Use ChildCount property instead.")]
349 public abstract UInt32 GetChildCount();
351 internal abstract View FindCurrentChildById(uint id);
353 internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
358 if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
360 base.OnParentResourcesChanged(values);
364 var innerKeys = new HashSet<string>();
365 var changedResources = new List<KeyValuePair<string, object>>();
366 foreach (KeyValuePair<string, object> c in XamlResources)
367 innerKeys.Add(c.Key);
368 foreach (KeyValuePair<string, object> value in values)
370 if (innerKeys.Add(value.Key))
371 changedResources.Add(value);
373 if (changedResources.Count != 0)
374 OnResourcesChanged(changedResources);
378 /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
380 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
381 [EditorBrowsable(EditorBrowsableState.Never)]
382 protected override void OnBindingContextChanged()
384 var gotBindingContext = false;
387 for (var index = 0; index < Children.Count; index++)
389 Element child = Children[index];
391 if (!gotBindingContext)
394 gotBindingContext = true;
397 SetChildInheritedBindingContext(child, bc);
399 base.OnBindingContextChanged();
402 private void DisposeIncludeChildren()
404 foreach (var child in Children)
406 child.DisposeIncludeChildren();
416 private void CopyChildren(Container other)
418 var childrenOfOtherView = new List<View>();
420 foreach (var child in other.Children)
422 childrenOfOtherView.Add(child);
425 foreach (var child in childrenOfOtherView)
431 private void ReplaceChild(View child, View newChild)
433 int indexOfView = Children.FindIndex((View v) => { return v == child; });
435 var childrenNeedtoReAdd = new Stack<View>();
437 for (int i = Children.Count - 1; i > indexOfView; i--)
439 childrenNeedtoReAdd.Push(Children[i]);
445 childrenNeedtoReAdd.Push(newChild);
447 while (0 < childrenNeedtoReAdd.Count)
449 Add(childrenNeedtoReAdd.Pop());
453 private void ReplaceBindingElementInWholeTree(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
457 ReplaceBindingElement(oldNameScope, newNameScope);
459 foreach (var child in Children)
461 child.ReplaceBindingElementInWholeTree(oldNameScope, newNameScope);
466 } // namespace Tizen.NUI