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
19 // public static readonly BindableProperty MenuProperty = BindableProperty.CreateAttached(nameof(Menu), typeof(Menu), typeof(Element), null);
21 // public static Menu GetMenu(BindableObject bindable)
23 // return (Menu)bindable.GetValue(MenuProperty);
26 // public static void SetMenu(BindableObject bindable, Menu menu)
28 // bindable.SetValue(MenuProperty, menu);
31 internal static readonly ReadOnlyCollection<Element> EmptyChildren = new ReadOnlyCollection<Element>(new Element[0]);
34 /// Identifies the ClassId bindable property.
36 internal static readonly BindableProperty ClassIdProperty = BindableProperty.Create("ClassId", typeof(string), typeof(Tizen.NUI.BaseComponents.View), null);
40 IList<BindableObject> _bindableResources;
42 List<Action<object, ResourcesChangedEventArgs>> _changeHandlers;
44 Dictionary<BindableProperty, string> _dynamicResources;
46 IEffectControlProvider _effectControlProvider;
48 TrackableCollection<Effect> _effects;
52 Element _parentOverride;
59 /// Gets or sets a value that allows the automation framework to find and interact with this element.
61 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
62 [EditorBrowsable(EditorBrowsableState.Never)]
63 public string AutomationId
65 get { return _automationId; }
68 if (_automationId != null)
69 throw new InvalidOperationException("AutomationId may only be set one time");
70 _automationId = value;
75 /// Gets or sets a value used to identify a collection of semantically similar elements.
77 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
78 [EditorBrowsable(EditorBrowsableState.Never)]
81 get { return (string)GetValue(ClassIdProperty); }
82 set { SetValue(ClassIdProperty, value); }
85 internal IList<Effect> Effects
91 _effects = new TrackableCollection<Effect>();
92 _effects.CollectionChanged += EffectsOnCollectionChanged;
93 _effects.Clearing += EffectsOnClearing;
100 /// Gets a value that can be used to uniquely identify an element through the run of an application.
102 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
103 [EditorBrowsable(EditorBrowsableState.Never)]
109 _id = Guid.NewGuid();
115 /// Gets the element which is the closest ancestor of this element that is a BaseHandle.
117 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
118 [EditorBrowsable(EditorBrowsableState.Never)]
119 [Obsolete("ParentView is obsolete as of version 2.1.0. Please use Parent instead.")]
120 public BaseHandle ParentView
124 Element parent = Parent;
125 while (parent != null)
127 var parentView = parent as BaseHandle;
128 if (parentView != null)
130 parent = parent.RealParent;
137 /// Gets or sets a user defined value to uniquely identify the element.
139 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
140 [EditorBrowsable(EditorBrowsableState.Never)]
141 public string StyleId
143 get { return _styleId; }
146 if (_styleId == value)
149 OnPropertyChanging();
155 internal virtual ReadOnlyCollection<Element> LogicalChildrenInternal => EmptyChildren;
158 /// For internal use.
160 [EditorBrowsable(EditorBrowsableState.Never)]
161 public ReadOnlyCollection<Element> LogicalChildren => LogicalChildrenInternal;
163 internal bool Owned { get; set; }
165 internal Element ParentOverride
167 get { return _parentOverride; }
170 if (_parentOverride == value)
173 bool emitChange = Parent != value;
176 OnPropertyChanging(nameof(Parent));
178 _parentOverride = value;
181 OnPropertyChanged(nameof(Parent));
186 /// For internal use.
188 internal IPlatform Platform
192 if (_platform == null && RealParent != null)
193 return RealParent.Platform;
198 if (_platform == value)
201 PlatformSet?.Invoke(this, EventArgs.Empty);
202 foreach (Element descendant in Descendants())
204 descendant._platform = _platform;
205 descendant.PlatformSet?.Invoke(this, EventArgs.Empty);
211 /// For internal use.
213 [EditorBrowsable(EditorBrowsableState.Never)]
214 public Element RealParent { get; private set; }
216 Dictionary<BindableProperty, string> DynamicResources
218 get { return _dynamicResources ?? (_dynamicResources = new Dictionary<BindableProperty, string>()); }
221 void IElement.AddResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
223 _changeHandlers = _changeHandlers ?? new List<Action<object, ResourcesChangedEventArgs>>(2);
224 _changeHandlers.Add(onchanged);
228 /// Gets or sets the parent element of the element.
230 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
231 [EditorBrowsable(EditorBrowsableState.Never)]
232 public Element Parent
234 get { return _parentOverride ?? RealParent; }
237 if (RealParent == value)
240 OnPropertyChanging();
242 if (RealParent != null)
243 ((IElement)RealParent).RemoveResourcesChangedListener(OnParentResourcesChanged);
245 if (RealParent != null)
247 OnParentResourcesChanged(RealParent?.GetMergedResources());
248 ((IElement)RealParent).AddResourcesChangedListener(OnParentResourcesChanged);
251 object context = value != null ? value.BindingContext : null;
254 value.SetChildInheritedBindingContext(this, context);
258 SetInheritedBindingContext(this, null);
263 if (RealParent != null)
265 IPlatform platform = RealParent.Platform;
266 if (platform != null)
274 void IElement.RemoveResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
276 if (_changeHandlers == null)
278 _changeHandlers.Remove(onchanged);
282 /// For internal use.
284 internal IEffectControlProvider EffectControlProvider
286 get { return _effectControlProvider; }
289 if (_effectControlProvider == value)
291 if (_effectControlProvider != null && _effects != null)
293 foreach (Effect effect in _effects)
294 effect?.SendDetached();
296 _effectControlProvider = value;
297 if (_effectControlProvider != null && _effects != null)
299 foreach (Effect effect in _effects)
302 AttachEffect(effect);
308 //void IElementController.SetValueFromRenderer(BindableProperty property, object value) => SetValueFromRenderer(property, value);
311 /// Sets the value of the specified property.
313 /// <param name="property">The BindableProperty on which to assign a value.</param>
314 /// <param name="value">The value to set.</param>
315 internal void SetValueFromRenderer(BindableProperty property, object value)
317 SetValueCore(property, value);
321 /// Sets the value of the propertyKey.
323 /// <param name="property">The BindablePropertyKey on which to assign a value.</param>
324 /// <param name="value">The value to set.</param>
325 internal void SetValueFromRenderer(BindablePropertyKey property, object value)
327 SetValueCore(property, value);
331 /// For internal use.
333 /// <param name="name">The nameof the effect</param>
334 /// <returns>true if attached</returns>
335 [EditorBrowsable(EditorBrowsableState.Never)]
336 public bool EffectIsAttached(string name)
338 foreach (var effect in Effects)
340 if (effect.ResolveId == name)
346 object INameScope.FindByName(string name)
348 INameScope namescope = GetNameScope();
349 if (namescope == null)
355 return namescope.FindByName(name);
359 void INameScope.RegisterName(string name, object scopedElement)
361 INameScope namescope = GetNameScope();
362 if (namescope == null)
363 throw new InvalidOperationException("this element is not in a namescope");
364 namescope.RegisterName(name, scopedElement);
368 void INameScope.RegisterName(string name, object scopedElement, IXmlLineInfo xmlLineInfo)
370 INameScope namescope = GetNameScope();
371 if (namescope == null)
372 throw new InvalidOperationException("this element is not in a namescope");
373 namescope.RegisterName(name, scopedElement, xmlLineInfo);
376 void INameScope.UnregisterName(string name)
378 INameScope namescope = GetNameScope();
379 if (namescope == null)
380 throw new InvalidOperationException("this element is not in a namescope");
381 namescope.UnregisterName(name);
384 internal event EventHandler<ElementEventArgs> ChildAdded;
386 internal event EventHandler<ElementEventArgs> ChildRemoved;
388 internal event EventHandler<ElementEventArgs> DescendantAdded;
390 internal event EventHandler<ElementEventArgs> DescendantRemoved;
393 /// Removes a previously set dynamic resource.
395 /// <param name="property">The BindableProperty from which to remove the DynamicResource.</param>
396 internal new void RemoveDynamicResource(BindableProperty property)
398 base.RemoveDynamicResource(property);
402 /// Sets the BindableProperty property of this element to be updated via the DynamicResource with the provided key.
404 /// <param name="property">The BindableProperty.</param>
405 /// <param name="key">The key of the DynamicResource</param>
406 internal new void SetDynamicResource(BindableProperty property, string key)
408 base.SetDynamicResource(property, key);
412 /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
414 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
415 [EditorBrowsable(EditorBrowsableState.Never)]
416 protected override void OnBindingContextChanged()
418 var gotBindingContext = false;
421 for (var index = 0; index < LogicalChildrenInternal.Count; index++)
423 Element child = LogicalChildrenInternal[index];
425 if (!gotBindingContext)
428 gotBindingContext = true;
431 SetChildInheritedBindingContext(child, bc);
434 if (_bindableResources != null)
435 foreach (BindableObject item in _bindableResources)
437 SetInheritedBindingContext(item, BindingContext);
440 base.OnBindingContextChanged();
444 /// Invoked whenever the ChildAdded event needs to be emitted.Implement this method to add class handling for this event.
446 /// <param name="child">The element that was added.</param>
447 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
448 [EditorBrowsable(EditorBrowsableState.Never)]
449 protected virtual void OnChildAdded(Element child)
452 if (Platform != null)
453 child.Platform = Platform;
455 child.ApplyBindings(skipBindingContext: false, fromBindingContextChanged:true);
457 ChildAdded?.Invoke(this, new ElementEventArgs(child));
459 OnDescendantAdded(child);
460 foreach (Element element in child.Descendants())
461 OnDescendantAdded(element);
465 /// Invoked whenever the ChildRemoved event needs to be emitted.Implement this method to add class handling for this event.
467 /// <param name="child">The element that was removed.</param>
468 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
469 [EditorBrowsable(EditorBrowsableState.Never)]
470 protected virtual void OnChildRemoved(Element child)
474 ChildRemoved?.Invoke(child, new ElementEventArgs(child));
476 OnDescendantRemoved(child);
477 foreach (Element element in child.Descendants())
478 OnDescendantRemoved(element);
482 /// 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.
484 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
485 [EditorBrowsable(EditorBrowsableState.Never)]
486 protected virtual void OnParentSet()
488 ParentSet?.Invoke(this, EventArgs.Empty);
489 // ApplyStyleSheetsOnParentSet();
493 /// Method that is called when a bound property is changed.
495 /// <param name="propertyName">The name of the bound property that changed.</param>
496 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
497 [EditorBrowsable(EditorBrowsableState.Never)]
498 protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
500 base.OnPropertyChanged(propertyName);
502 if (_effects == null || _effects.Count == 0)
505 var args = new PropertyChangedEventArgs(propertyName);
506 foreach (Effect effect in _effects)
508 effect?.SendOnElementPropertyChanged(args);
513 /// For internal use.
515 /// <returns>the elements</returns>
516 [EditorBrowsable(EditorBrowsableState.Never)]
517 public IEnumerable<Element> Descendants()
519 var queue = new Queue<Element>(16);
522 while (queue.Count > 0)
524 ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
525 for (var i = 0; i < children.Count; i++)
527 Element child = children[i];
529 queue.Enqueue(child);
534 internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
536 // if (e == ResourcesChangedEventArgs.StyleSheets)
537 // // ApplyStyleSheetsOnParentSet();
539 // OnParentResourcesChanged(e.Values);
542 internal virtual void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
544 OnResourcesChanged(values);
547 internal override void OnRemoveDynamicResource(BindableProperty property)
549 DynamicResources.Remove(property);
551 if (DynamicResources.Count == 0)
552 _dynamicResources = null;
553 base.OnRemoveDynamicResource(property);
556 internal virtual void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
558 OnResourcesChanged(e.Values);
561 internal void OnResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
565 if (_changeHandlers != null)
566 foreach (Action<object, ResourcesChangedEventArgs> handler in _changeHandlers)
567 handler(this, new ResourcesChangedEventArgs(values));
568 if (_dynamicResources == null)
570 if (_bindableResources == null)
571 _bindableResources = new List<BindableObject>();
572 foreach (KeyValuePair<string, object> value in values)
574 List<BindableProperty> changedResources = null;
575 foreach (KeyValuePair<BindableProperty, string> dynR in DynamicResources)
577 // when the DynamicResource bound to a BindableProperty is
578 // changing then the BindableProperty needs to be refreshed;
579 // The .Value is the name of DynamicResouce to which the BindableProperty is bound.
580 // The .Key is the name of the DynamicResource whose value is changing.
581 if (dynR.Value != value.Key)
583 changedResources = changedResources ?? new List<BindableProperty>();
584 changedResources.Add(dynR.Key);
586 if (changedResources == null)
588 foreach (BindableProperty changedResource in changedResources)
589 OnResourceChanged(changedResource, value.Value);
591 var bindableObject = value.Value as BindableObject;
592 if (bindableObject != null && (bindableObject as Element)?.Parent == null)
594 if (!_bindableResources.Contains(bindableObject))
595 _bindableResources.Add(bindableObject);
596 SetInheritedBindingContext(bindableObject, BindingContext);
601 internal override void OnSetDynamicResource(BindableProperty property, string key)
603 base.OnSetDynamicResource(property, key);
604 DynamicResources[property] = key;
606 if (this.TryGetResource(key, out value))
607 OnResourceChanged(property, value);
609 Tizen.NUI.Application.AddResourceChangedCallback(this, (this as Element).OnResourcesChanged);
612 internal event EventHandler ParentSet;
614 internal static void SetFlowDirectionFromParent(Element child)
619 /// For internal use.
621 [EditorBrowsable(EditorBrowsableState.Never)]
622 public event EventHandler PlatformSet;
624 internal virtual void SetChildInheritedBindingContext(Element child, object context)
626 SetInheritedBindingContext(child, context);
629 internal IEnumerable<Element> VisibleDescendants()
631 var queue = new Queue<Element>(16);
634 while (queue.Count > 0)
636 ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
637 for (var i = 0; i < children.Count; i++)
639 var child = children[i] as BaseHandle;
645 queue.Enqueue(child);
650 void AttachEffect(Effect effect)
652 if (_effectControlProvider == null)
654 if (effect.IsAttached)
655 throw new InvalidOperationException("Cannot attach Effect to multiple sources");
657 Effect effectToRegister = effect;
658 if (effect is RoutingEffect)
659 effectToRegister = ((RoutingEffect)effect).Inner;
660 _effectControlProvider.RegisterEffect(effectToRegister);
661 effectToRegister.Element = this;
662 effect.SendAttached();
665 void EffectsOnClearing(object sender, EventArgs eventArgs)
667 foreach (Effect effect in _effects)
669 effect?.ClearEffect();
673 void EffectsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
677 case NotifyCollectionChangedAction.Add:
678 foreach (Effect effect in e.NewItems)
680 AttachEffect(effect);
683 case NotifyCollectionChangedAction.Move:
685 case NotifyCollectionChangedAction.Remove:
686 foreach (Effect effect in e.OldItems)
688 effect.ClearEffect();
691 case NotifyCollectionChangedAction.Replace:
692 foreach (Effect effect in e.NewItems)
694 AttachEffect(effect);
696 foreach (Effect effect in e.OldItems)
698 effect.ClearEffect();
701 case NotifyCollectionChangedAction.Reset:
702 if (e.NewItems != null)
704 foreach (Effect effect in e.NewItems)
706 AttachEffect(effect);
709 if (e.OldItems != null)
711 foreach (Effect effect in e.OldItems)
713 effect.ClearEffect();
718 throw new ArgumentOutOfRangeException();
722 INameScope GetNameScope()
724 INameScope namescope = NameScope.GetNameScope(this);
725 Element p = RealParent;
726 while (namescope == null && p != null)
728 namescope = NameScope.GetNameScope(p);
734 void OnDescendantAdded(Element child)
736 DescendantAdded?.Invoke(this, new ElementEventArgs(child));
738 if (RealParent != null)
739 RealParent.OnDescendantAdded(child);
742 void OnDescendantRemoved(Element child)
744 DescendantRemoved?.Invoke(this, new ElementEventArgs(child));
746 if (RealParent != null)
747 RealParent.OnDescendantRemoved(child);
750 void OnResourceChanged(BindableProperty property, object value)
752 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearTwoWayBindings);