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 [Obsolete("ParentView is obsolete as of version 2.1.0. Please use Parent instead.")]
118 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
119 [EditorBrowsable(EditorBrowsableState.Never)]
120 public /*VisualElement*/BaseHandle ParentView
124 Element parent = Parent;
125 while (parent != null)
127 var parentView = parent as /*VisualElement*/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)
350 throw new InvalidOperationException("this element is not in a namescope");
351 return namescope.FindByName(name);
354 void INameScope.RegisterName(string name, object scopedElement)
356 INameScope namescope = GetNameScope();
357 if (namescope == null)
358 throw new InvalidOperationException("this element is not in a namescope");
359 namescope.RegisterName(name, scopedElement);
363 void INameScope.RegisterName(string name, object scopedElement, IXmlLineInfo xmlLineInfo)
365 INameScope namescope = GetNameScope();
366 if (namescope == null)
367 throw new InvalidOperationException("this element is not in a namescope");
368 namescope.RegisterName(name, scopedElement, xmlLineInfo);
371 void INameScope.UnregisterName(string name)
373 INameScope namescope = GetNameScope();
374 if (namescope == null)
375 throw new InvalidOperationException("this element is not in a namescope");
376 namescope.UnregisterName(name);
379 internal event EventHandler<ElementEventArgs> ChildAdded;
381 internal event EventHandler<ElementEventArgs> ChildRemoved;
383 internal event EventHandler<ElementEventArgs> DescendantAdded;
385 internal event EventHandler<ElementEventArgs> DescendantRemoved;
388 /// Removes a previously set dynamic resource.
390 /// <param name="property">The BindableProperty from which to remove the DynamicResource.</param>
391 internal new void RemoveDynamicResource(BindableProperty property)
393 base.RemoveDynamicResource(property);
397 /// Sets the BindableProperty property of this element to be updated via the DynamicResource with the provided key.
399 /// <param name="property">The BindableProperty.</param>
400 /// <param name="key">The key of the DynamicResource</param>
401 internal new void SetDynamicResource(BindableProperty property, string key)
403 base.SetDynamicResource(property, key);
407 /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
409 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
410 [EditorBrowsable(EditorBrowsableState.Never)]
411 protected override void OnBindingContextChanged()
413 var gotBindingContext = false;
416 for (var index = 0; index < LogicalChildrenInternal.Count; index++)
418 Element child = LogicalChildrenInternal[index];
420 if (!gotBindingContext)
423 gotBindingContext = true;
426 SetChildInheritedBindingContext(child, bc);
429 if (_bindableResources != null)
430 foreach (BindableObject item in _bindableResources)
432 SetInheritedBindingContext(item, BindingContext);
435 base.OnBindingContextChanged();
439 /// Invoked whenever the ChildAdded event needs to be emitted.Implement this method to add class handling for this event.
441 /// <param name="child">The element that was added.</param>
442 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
443 [EditorBrowsable(EditorBrowsableState.Never)]
444 protected virtual void OnChildAdded(Element child)
447 if (Platform != null)
448 child.Platform = Platform;
450 child.ApplyBindings(skipBindingContext: false, fromBindingContextChanged:true);
452 ChildAdded?.Invoke(this, new ElementEventArgs(child));
454 OnDescendantAdded(child);
455 foreach (Element element in child.Descendants())
456 OnDescendantAdded(element);
460 /// Invoked whenever the ChildRemoved event needs to be emitted.Implement this method to add class handling for this event.
462 /// <param name="child">The element that was removed.</param>
463 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
464 [EditorBrowsable(EditorBrowsableState.Never)]
465 protected virtual void OnChildRemoved(Element child)
469 ChildRemoved?.Invoke(child, new ElementEventArgs(child));
471 OnDescendantRemoved(child);
472 foreach (Element element in child.Descendants())
473 OnDescendantRemoved(element);
477 /// 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.
479 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
480 [EditorBrowsable(EditorBrowsableState.Never)]
481 protected virtual void OnParentSet()
483 ParentSet?.Invoke(this, EventArgs.Empty);
484 // ApplyStyleSheetsOnParentSet();
488 /// Method that is called when a bound property is changed.
490 /// <param name="propertyName">The name of the bound property that changed.</param>
491 /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
492 [EditorBrowsable(EditorBrowsableState.Never)]
493 protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
495 base.OnPropertyChanged(propertyName);
497 if (_effects == null || _effects.Count == 0)
500 var args = new PropertyChangedEventArgs(propertyName);
501 foreach (Effect effect in _effects)
503 effect?.SendOnElementPropertyChanged(args);
508 /// For internal use.
510 /// <returns>the elements</returns>
511 [EditorBrowsable(EditorBrowsableState.Never)]
512 public IEnumerable<Element> Descendants()
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 Element child = children[i];
524 queue.Enqueue(child);
529 internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
531 // if (e == ResourcesChangedEventArgs.StyleSheets)
532 // // ApplyStyleSheetsOnParentSet();
534 // OnParentResourcesChanged(e.Values);
537 internal virtual void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
539 OnResourcesChanged(values);
542 internal override void OnRemoveDynamicResource(BindableProperty property)
544 DynamicResources.Remove(property);
546 if (DynamicResources.Count == 0)
547 _dynamicResources = null;
548 base.OnRemoveDynamicResource(property);
551 internal virtual void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
553 OnResourcesChanged(e.Values);
556 internal void OnResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
560 if (_changeHandlers != null)
561 foreach (Action<object, ResourcesChangedEventArgs> handler in _changeHandlers)
562 handler(this, new ResourcesChangedEventArgs(values));
563 if (_dynamicResources == null)
565 if (_bindableResources == null)
566 _bindableResources = new List<BindableObject>();
567 foreach (KeyValuePair<string, object> value in values)
569 List<BindableProperty> changedResources = null;
570 foreach (KeyValuePair<BindableProperty, string> dynR in DynamicResources)
572 // when the DynamicResource bound to a BindableProperty is
573 // changing then the BindableProperty needs to be refreshed;
574 // The .Value is the name of DynamicResouce to which the BindableProperty is bound.
575 // The .Key is the name of the DynamicResource whose value is changing.
576 if (dynR.Value != value.Key)
578 changedResources = changedResources ?? new List<BindableProperty>();
579 changedResources.Add(dynR.Key);
581 if (changedResources == null)
583 foreach (BindableProperty changedResource in changedResources)
584 OnResourceChanged(changedResource, value.Value);
586 var bindableObject = value.Value as BindableObject;
587 if (bindableObject != null && (bindableObject as Element)?.Parent == null)
589 if (!_bindableResources.Contains(bindableObject))
590 _bindableResources.Add(bindableObject);
591 SetInheritedBindingContext(bindableObject, BindingContext);
596 internal override void OnSetDynamicResource(BindableProperty property, string key)
598 base.OnSetDynamicResource(property, key);
599 DynamicResources[property] = key;
601 if (this.TryGetResource(key, out value))
602 OnResourceChanged(property, value);
605 internal event EventHandler ParentSet;
607 internal static void SetFlowDirectionFromParent(Element child)
609 // IFlowDirectionController controller = child as IFlowDirectionController;
610 // if (controller == null)
613 // if (controller.EffectiveFlowDirection.IsImplicit())
615 // var parentView = child.Parent as IFlowDirectionController;
616 // if (parentView == null)
619 // var flowDirection = parentView.EffectiveFlowDirection.ToFlowDirection();
621 // if (flowDirection != controller.EffectiveFlowDirection.ToFlowDirection())
623 // controller.EffectiveFlowDirection = flowDirection.ToEffectiveFlowDirection();
629 /// For internal use.
631 [EditorBrowsable(EditorBrowsableState.Never)]
632 public event EventHandler PlatformSet;
634 internal virtual void SetChildInheritedBindingContext(Element child, object context)
636 SetInheritedBindingContext(child, context);
639 internal IEnumerable<Element> VisibleDescendants()
641 var queue = new Queue<Element>(16);
644 while (queue.Count > 0)
646 ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
647 for (var i = 0; i < children.Count; i++)
649 var child = children[i] as /*VisualElement*/BaseHandle;
650 if (child == null /*|| !child.IsVisible*/)
653 queue.Enqueue(child);
658 void AttachEffect(Effect effect)
660 if (_effectControlProvider == null)
662 if (effect.IsAttached)
663 throw new InvalidOperationException("Cannot attach Effect to multiple sources");
665 Effect effectToRegister = effect;
666 if (effect is RoutingEffect)
667 effectToRegister = ((RoutingEffect)effect).Inner;
668 _effectControlProvider.RegisterEffect(effectToRegister);
669 effectToRegister.Element = this;
670 effect.SendAttached();
673 void EffectsOnClearing(object sender, EventArgs eventArgs)
675 foreach (Effect effect in _effects)
677 effect?.ClearEffect();
681 void EffectsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
685 case NotifyCollectionChangedAction.Add:
686 foreach (Effect effect in e.NewItems)
688 AttachEffect(effect);
691 case NotifyCollectionChangedAction.Move:
693 case NotifyCollectionChangedAction.Remove:
694 foreach (Effect effect in e.OldItems)
696 effect.ClearEffect();
699 case NotifyCollectionChangedAction.Replace:
700 foreach (Effect effect in e.NewItems)
702 AttachEffect(effect);
704 foreach (Effect effect in e.OldItems)
706 effect.ClearEffect();
709 case NotifyCollectionChangedAction.Reset:
710 if (e.NewItems != null)
712 foreach (Effect effect in e.NewItems)
714 AttachEffect(effect);
717 if (e.OldItems != null)
719 foreach (Effect effect in e.OldItems)
721 effect.ClearEffect();
726 throw new ArgumentOutOfRangeException();
730 INameScope GetNameScope()
732 INameScope namescope = NameScope.GetNameScope(this);
733 Element p = RealParent;
734 while (namescope == null && p != null)
736 namescope = NameScope.GetNameScope(p);
742 void OnDescendantAdded(Element child)
744 DescendantAdded?.Invoke(this, new ElementEventArgs(child));
746 if (RealParent != null)
747 RealParent.OnDescendantAdded(child);
750 void OnDescendantRemoved(Element child)
752 DescendantRemoved?.Invoke(this, new ElementEventArgs(child));
754 if (RealParent != null)
755 RealParent.OnDescendantRemoved(child);
758 void OnResourceChanged(BindableProperty property, object value)
760 SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearTwoWayBindings);