namespace Avalonia.Controls { using System; /// /// Defines the available docking modes for a control in a . /// public enum Dock { Left = 0, Bottom, Right, Top } /// /// A panel which arranges its children at the top, bottom, left, right or center. /// public class DockPanel : Panel { /// /// Defines the Dock attached property. /// public static readonly AttachedProperty DockProperty = AvaloniaProperty.RegisterAttached("Dock"); /// /// Defines the property. /// public static readonly StyledProperty LastChildFillProperty = AvaloniaProperty.Register( nameof(LastChildFillProperty), defaultValue: true); /// /// Initializes static members of the class. /// static DockPanel() { AffectsArrange(DockProperty); } /// /// Gets the value of the Dock attached property on the specified control. /// /// The control. /// The Dock attached property. public static Dock GetDock(Control control) { return control.GetValue(DockProperty); } /// /// Sets the value of the Dock attached property on the specified control. /// /// The control. /// The value of the Dock property. public static void SetDock(Control control, Dock value) { control.SetValue(DockProperty, value); } /// /// Gets or sets a value which indicates whether the last child of the /// fills the remaining space in the panel. /// public bool LastChildFill { get { return GetValue(LastChildFillProperty); } set { SetValue(LastChildFillProperty, value); } } /// protected override Size MeasureOverride(Size constraint) { double usedWidth = 0.0; double usedHeight = 0.0; double maximumWidth = 0.0; double maximumHeight = 0.0; // Measure each of the Children foreach (Control element in Children) { // Get the child's desired size Size remainingSize = new Size( Math.Max(0.0, constraint.Width - usedWidth), Math.Max(0.0, constraint.Height - usedHeight)); element.Measure(remainingSize); Size desiredSize = element.DesiredSize; // Decrease the remaining space for the rest of the children switch (GetDock(element)) { case Dock.Left: case Dock.Right: maximumHeight = Math.Max(maximumHeight, usedHeight + desiredSize.Height); usedWidth += desiredSize.Width; break; case Dock.Top: case Dock.Bottom: maximumWidth = Math.Max(maximumWidth, usedWidth + desiredSize.Width); usedHeight += desiredSize.Height; break; } } maximumWidth = Math.Max(maximumWidth, usedWidth); maximumHeight = Math.Max(maximumHeight, usedHeight); return new Size(maximumWidth, maximumHeight); } /// protected override Size ArrangeOverride(Size arrangeSize) { double left = 0.0; double top = 0.0; double right = 0.0; double bottom = 0.0; // Arrange each of the Children var children = Children; int dockedCount = children.Count - (LastChildFill ? 1 : 0); int index = 0; foreach (Control element in children) { // Determine the remaining space left to arrange the element Rect remainingRect = new Rect( left, top, Math.Max(0.0, arrangeSize.Width - left - right), Math.Max(0.0, arrangeSize.Height - top - bottom)); // Trim the remaining Rect to the docked size of the element // (unless the element should fill the remaining space because // of LastChildFill) if (index < dockedCount) { Size desiredSize = element.DesiredSize; switch (GetDock(element)) { case Dock.Left: left += desiredSize.Width; remainingRect = remainingRect.WithWidth(desiredSize.Width); break; case Dock.Top: top += desiredSize.Height; remainingRect = remainingRect.WithHeight(desiredSize.Height); break; case Dock.Right: right += desiredSize.Width; remainingRect = new Rect( Math.Max(0.0, arrangeSize.Width - right), remainingRect.Y, desiredSize.Width, remainingRect.Height); break; case Dock.Bottom: bottom += desiredSize.Height; remainingRect = new Rect( remainingRect.X, Math.Max(0.0, arrangeSize.Height - bottom), remainingRect.Width, desiredSize.Height); break; } } element.Arrange(remainingRect); index++; } return arrangeSize; } } }