2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
4 using System.Collections.Specialized;
5 using System.ComponentModel;
6 using System.Runtime.CompilerServices;
8 using Tizen.NUI.Binding.Internals;
10 namespace Tizen.NUI.Binding
13 /// Provides the base class for all Tizen.NUI.Binding hierarchal elements. This class contains all the methods and properties required to represent an element in the Tizen.NUI.Binding hierarchy.
15 [EditorBrowsable(EditorBrowsableState.Never)]
16 public abstract partial class Element : BindableObject, IElement, INameScope, IElementController
18 internal static readonly ReadOnlyCollection<Element> EmptyChildren = new ReadOnlyCollection<Element>(System.Array.Empty<Element>());
21 /// Identifies the ClassId bindable property.
23 internal static readonly BindableProperty ClassIdProperty = BindableProperty.Create(nameof(ClassId), typeof(string), typeof(Tizen.NUI.BaseComponents.View), null);
27 IList<BindableObject> _bindableResources;
29 List<Action<object, ResourcesChangedEventArgs>> _changeHandlers;
31 Dictionary<BindableProperty, string> _dynamicResources;
35 Element _parentOverride;
40 /// Gets or sets a value that allows the automation framework to find and interact with this element.
42 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
43 [EditorBrowsable(EditorBrowsableState.Never)]
44 public string AutomationId
46 get { return _automationId; }
49 if (_automationId != null)
50 throw new InvalidOperationException("AutomationId may only be set one time");
51 _automationId = value;
56 /// Gets or sets a value used to identify a collection of semantically similar elements.
58 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
59 [EditorBrowsable(EditorBrowsableState.Never)]
62 get { return (string)GetValue(ClassIdProperty); }
63 set { SetValue(ClassIdProperty, value); }
67 /// Gets a value that can be used to uniquely identify an element through the run of an application.
69 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
70 [EditorBrowsable(EditorBrowsableState.Never)]
82 /// Gets the element which is the closest ancestor of this element that is a BaseHandle.
84 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
85 [EditorBrowsable(EditorBrowsableState.Never)]
86 [Obsolete("ParentView is obsolete as of version 2.1.0. Please use Parent instead.")]
87 public BaseHandle ParentView
91 Element parent = Parent;
92 while (parent != null)
94 var parentView = parent as BaseHandle;
95 if (parentView != null)
97 parent = parent.RealParent;
104 /// Gets or sets a user defined value to uniquely identify the element.
106 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
107 [EditorBrowsable(EditorBrowsableState.Never)]
108 public string StyleId
110 get { return _styleId; }
113 if (_styleId == value)
116 OnPropertyChanging();
122 internal virtual ReadOnlyCollection<Element> LogicalChildrenInternal => EmptyChildren;
125 /// For internal use.
127 [EditorBrowsable(EditorBrowsableState.Never)]
128 public ReadOnlyCollection<Element> LogicalChildren => LogicalChildrenInternal;
130 internal bool Owned { get; set; }
132 internal Element ParentOverride
134 get { return _parentOverride; }
137 if (_parentOverride == value)
140 bool emitChange = Parent != value;
143 OnPropertyChanging(nameof(Parent));
145 _parentOverride = value;
148 OnPropertyChanged(nameof(Parent));
153 /// For internal use.
155 [EditorBrowsable(EditorBrowsableState.Never)]
156 public Element RealParent { get; private set; }
158 Dictionary<BindableProperty, string> DynamicResources
160 get { return _dynamicResources ?? (_dynamicResources = new Dictionary<BindableProperty, string>()); }
163 void IElement.AddResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
165 _changeHandlers = _changeHandlers ?? new List<Action<object, ResourcesChangedEventArgs>>(2);
166 _changeHandlers.Add(onchanged);
170 /// Gets or sets the parent element of the element.
172 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
173 [EditorBrowsable(EditorBrowsableState.Never)]
174 public Element Parent
176 get { return _parentOverride ?? RealParent; }
179 if (RealParent == value)
182 OnPropertyChanging();
184 if (RealParent != null)
185 ((IElement)RealParent).RemoveResourcesChangedListener(OnParentResourcesChanged);
187 if (RealParent != null)
189 OnParentResourcesChanged(RealParent?.GetMergedResources());
190 ((IElement)RealParent).AddResourcesChangedListener(OnParentResourcesChanged);
193 object context = value != null ? value.BindingContext : null;
196 value.SetChildInheritedBindingContext(this, context);
200 SetInheritedBindingContext(this, null);
209 void IElement.RemoveResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
211 if (_changeHandlers == null)
213 _changeHandlers.Remove(onchanged);
216 //void IElementController.SetValueFromRenderer(BindableProperty property, object value) => SetValueFromRenderer(property, value);
219 /// Sets the value of the specified property.
221 /// <param name="property">The BindableProperty on which to assign a value.</param>
222 /// <param name="value">The value to set.</param>
223 internal void SetValueFromRenderer(BindableProperty property, object value)
225 SetValueCore(property, value);
229 /// Sets the value of the propertyKey.
231 /// <param name="property">The BindablePropertyKey on which to assign a value.</param>
232 /// <param name="value">The value to set.</param>
233 internal void SetValueFromRenderer(BindablePropertyKey property, object value)
235 SetValueCore(property, value);
238 object INameScope.FindByName(string name)
240 INameScope namescope = GetNameScope();
241 if (namescope == null)
247 return namescope.FindByName(name);
251 void INameScope.RegisterName(string name, object scopedElement)
253 INameScope namescope = GetNameScope();
254 if (namescope == null)
255 throw new InvalidOperationException("this element is not in a namescope");
256 namescope.RegisterName(name, scopedElement);
260 void INameScope.RegisterName(string name, object scopedElement, IXmlLineInfo xmlLineInfo)
262 INameScope namescope = GetNameScope();
263 if (namescope == null)
264 throw new InvalidOperationException("this element is not in a namescope");
265 namescope.RegisterName(name, scopedElement, xmlLineInfo);
268 void INameScope.UnregisterName(string name)
270 INameScope namescope = GetNameScope();
271 if (namescope == null)
272 throw new InvalidOperationException("this element is not in a namescope");
273 namescope.UnregisterName(name);
276 internal event EventHandler<ElementEventArgs> ChildAdded;
278 internal event EventHandler<ElementEventArgs> ChildRemoved;
280 internal event EventHandler<ElementEventArgs> DescendantAdded;
282 internal event EventHandler<ElementEventArgs> DescendantRemoved;
285 /// Removes a previously set dynamic resource.
287 /// <param name="property">The BindableProperty from which to remove the DynamicResource.</param>
288 internal new void RemoveDynamicResource(BindableProperty property)
290 base.RemoveDynamicResource(property);
294 /// Sets the BindableProperty property of this element to be updated via the DynamicResource with the provided key.
296 /// <param name="property">The BindableProperty.</param>
297 /// <param name="key">The key of the DynamicResource</param>
298 internal new void SetDynamicResource(BindableProperty property, string key)
300 base.SetDynamicResource(property, key);
304 /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
306 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
307 [EditorBrowsable(EditorBrowsableState.Never)]
308 protected override void OnBindingContextChanged()
310 var gotBindingContext = false;
313 for (var index = 0; index < LogicalChildrenInternal.Count; index++)
315 Element child = LogicalChildrenInternal[index];
317 if (!gotBindingContext)
320 gotBindingContext = true;
323 SetChildInheritedBindingContext(child, bc);
326 if (_bindableResources != null)
327 foreach (BindableObject item in _bindableResources)
329 SetInheritedBindingContext(item, BindingContext);
332 base.OnBindingContextChanged();
336 /// Invoked whenever the ChildAdded event needs to be emitted.Implement this method to add class handling for this event.
338 /// <param name="child">The element that was added.</param>
339 /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception>
340 /// This will be public opened later after ACR done. Before ACR, need to be hidden as inhouse API.
341 [EditorBrowsable(EditorBrowsableState.Never)]
342 protected virtual void OnChildAdded(Element child)
346 throw new ArgumentNullException(nameof(child));
351 child.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
353 ChildAdded?.Invoke(this, new ElementEventArgs(child));
355 OnDescendantAdded(child);
356 foreach (Element element in child.Descendants())
357 OnDescendantAdded(element);
361 /// Invoked whenever the ChildRemoved event needs to be emitted.Implement this method to add class handling for this event.
363 /// <param name="child">The element that was removed.</param>
364 /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception>
365 /// This will be public opened later after ACR done. Before ACR, need to be hidden as inhouse API.
366 [EditorBrowsable(EditorBrowsableState.Never)]
367 protected virtual void OnChildRemoved(Element child)
371 throw new ArgumentNullException(nameof(child));
376 ChildRemoved?.Invoke(child, new ElementEventArgs(child));
378 OnDescendantRemoved(child);
379 foreach (Element element in child.Descendants())
380 OnDescendantRemoved(element);
384 /// Invoked whenever the Parent of an element is set.Implement this method in order to add behavior when the element is added to a parent.
386 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
387 [EditorBrowsable(EditorBrowsableState.Never)]
388 protected virtual void OnParentSet()
390 ParentSet?.Invoke(this, EventArgs.Empty);
391 // ApplyStyleSheetsOnParentSet();
395 /// Method that is called when a bound property is changed.
397 /// <param name="propertyName">The name of the bound property that changed.</param>
398 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
399 [EditorBrowsable(EditorBrowsableState.Never)]
400 protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
402 base.OnPropertyChanged(propertyName);
406 /// For internal use.
408 /// <returns>the elements</returns>
409 [EditorBrowsable(EditorBrowsableState.Never)]
410 public IEnumerable<Element> Descendants()
412 var queue = new Queue<Element>(16);
415 while (queue.Count > 0)
417 ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
418 for (var i = 0; i < children.Count; i++)
420 Element child = children[i];
422 queue.Enqueue(child);
427 internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
429 // if (e == ResourcesChangedEventArgs.StyleSheets)
430 // // ApplyStyleSheetsOnParentSet();
432 // OnParentResourcesChanged(e.Values);
435 internal virtual void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
437 OnResourcesChanged(values);
440 internal override void OnRemoveDynamicResource(BindableProperty property)
442 DynamicResources.Remove(property);
444 if (DynamicResources.Count == 0)
445 _dynamicResources = null;
446 base.OnRemoveDynamicResource(property);
449 internal virtual void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
451 OnResourcesChanged(e.Values);
454 internal void OnResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
458 if (_changeHandlers != null)
459 foreach (Action<object, ResourcesChangedEventArgs> handler in _changeHandlers)
460 handler(this, new ResourcesChangedEventArgs(values));
461 if (_dynamicResources == null)
463 if (_bindableResources == null)
464 _bindableResources = new List<BindableObject>();
465 foreach (KeyValuePair<string, object> value in values)
467 List<BindableProperty> changedResources = null;
468 foreach (KeyValuePair<BindableProperty, string> dynR in DynamicResources)
470 // when the DynamicResource bound to a BindableProperty is
471 // changing then the BindableProperty needs to be refreshed;
472 // The .Value is the name of DynamicResouce to which the BindableProperty is bound.
473 // The .Key is the name of the DynamicResource whose value is changing.
474 if (dynR.Value != value.Key)
476 changedResources = changedResources ?? new List<BindableProperty>();
477 changedResources.Add(dynR.Key);
479 if (changedResources == null)
481 foreach (BindableProperty changedResource in changedResources)
482 OnResourceChanged(changedResource, value.Value);
484 var bindableObject = value.Value as BindableObject;
485 if (bindableObject != null && (bindableObject as Element)?.Parent == null)
487 if (!_bindableResources.Contains(bindableObject))
488 _bindableResources.Add(bindableObject);
489 SetInheritedBindingContext(bindableObject, BindingContext);
494 internal override void OnSetDynamicResource(BindableProperty property, string key)
496 base.OnSetDynamicResource(property, key);
497 DynamicResources[property] = key;
499 if (this.TryGetResource(key, out value))
500 OnResourceChanged(property, value);
502 Tizen.NUI.Application.AddResourceChangedCallback(this, (this as Element).OnResourcesChanged);
505 internal event EventHandler ParentSet;
507 internal virtual void SetChildInheritedBindingContext(Element child, object context)
509 SetInheritedBindingContext(child, context);
512 internal IEnumerable<Element> VisibleDescendants()
514 var queue = new Queue<Element>(16);
517 while (queue.Count > 0)
519 ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
520 for (var i = 0; i < children.Count; i++)
522 var child = children[i] as BaseHandle;
528 queue.Enqueue(child);
533 INameScope GetNameScope()
535 INameScope namescope = NameScope.GetNameScope(this);
536 Element p = RealParent;
537 while (namescope == null && p != null)
539 namescope = NameScope.GetNameScope(p);
545 void OnDescendantAdded(Element child)
547 DescendantAdded?.Invoke(this, new ElementEventArgs(child));
549 if (RealParent != null)
550 RealParent.OnDescendantAdded(child);
553 void OnDescendantRemoved(Element child)
555 DescendantRemoved?.Invoke(this, new ElementEventArgs(child));
557 if (RealParent != null)
558 RealParent.OnDescendantRemoved(child);
561 void OnResourceChanged(BindableProperty property, object value)
563 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearTwoWayBindings);