// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Controls { using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using Perspex.Collections; /// /// Base class for controls that can contain multiple children. /// /// /// Controls can be added to a by adding them to its /// collection. All children are layed out to fill the panel. /// public class Panel : Control, IReparentingControl { private Controls children = new Controls(); private ILogical childLogicalParent; /// /// Initializes a new instance of the class. /// public Panel() { this.children.CollectionChanged += this.ChildrenChanged; this.childLogicalParent = this; } /// /// Gets or sets the children of the . /// /// /// Even though this property can be set, the setter is only intended for use in object /// initializers. Assigning to this property does not change the underlying collection, /// it simply clears the existing collection and adds the contents of the assigned /// collection. /// public Controls Children { get { return this.children; } set { Contract.Requires(value != null); this.ClearVisualChildren(); this.children.Clear(); this.children.AddRange(value); } } /// /// Requests that the visual children of the panel use another control as their logical /// parent. /// /// /// The logical parent for the visual children of the panel. /// /// /// The collection to modify. /// void IReparentingControl.ReparentLogicalChildren(ILogical logicalParent, IPerspexList children) { Contract.Requires(logicalParent != null); Contract.Requires(children != null); this.childLogicalParent = logicalParent; this.RedirectLogicalChildren(children); foreach (var control in this.Children) { ((ISetLogicalParent)control).SetParent(null); ((ISetLogicalParent)control).SetParent((IControl)logicalParent); children.Add(control); } } /// /// Clears for the specified controls. /// /// The controls. private void ClearLogicalParent(IEnumerable controls) { foreach (var control in controls) { ((ISetLogicalParent)control).SetParent(null); } } /// /// Sets for the specified controls. /// /// The controls. private void SetLogicalParent(IEnumerable controls) { var parent = this.childLogicalParent as Control; foreach (var control in controls) { ((ISetLogicalParent)control).SetParent(parent); } } /// /// Called when the collection changes. /// /// The event sender. /// The event args. private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) { List controls; // TODO: Handle Replace. switch (e.Action) { case NotifyCollectionChangedAction.Add: controls = e.NewItems.OfType().ToList(); this.SetLogicalParent(controls); this.AddVisualChildren(e.NewItems.OfType()); this.LogicalChildren.InsertRange(e.NewStartingIndex, controls); break; case NotifyCollectionChangedAction.Remove: controls = e.OldItems.OfType().ToList(); this.ClearLogicalParent(e.OldItems.OfType()); this.LogicalChildren.RemoveAll(controls); this.RemoveVisualChildren(e.OldItems.OfType()); break; case NotifyCollectionChangedAction.Reset: controls = e.OldItems.OfType().ToList(); this.ClearLogicalParent(controls); this.LogicalChildren.Clear(); this.ClearVisualChildren(); this.AddVisualChildren(this.children); break; } this.InvalidateMeasure(); } } }