| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- // Copyright (c) The Avalonia Project. All rights reserved.
- // Licensed under the MIT license. See licence.md file in the project root for full license information.
- using System;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Linq;
- using Avalonia.Media;
- using Avalonia.Metadata;
- namespace Avalonia.Controls
- {
- /// <summary>
- /// Base class for controls that can contain multiple children.
- /// </summary>
- /// <remarks>
- /// Controls can be added to a <see cref="Panel"/> by adding them to its <see cref="Children"/>
- /// collection. All children are layed out to fill the panel.
- /// </remarks>
- public class Panel : Control, IPanel
- {
- /// <summary>
- /// Defines the <see cref="Background"/> property.
- /// </summary>
- public static readonly StyledProperty<IBrush> BackgroundProperty =
- Border.BackgroundProperty.AddOwner<Panel>();
- /// <summary>
- /// Initializes static members of the <see cref="Panel"/> class.
- /// </summary>
- static Panel()
- {
- AffectsRender<Panel>(BackgroundProperty);
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="Panel"/> class.
- /// </summary>
- public Panel()
- {
- Children.CollectionChanged += ChildrenChanged;
- }
- /// <summary>
- /// Gets the children of the <see cref="Panel"/>.
- /// </summary>
- [Content]
- public Controls Children { get; } = new Controls();
- /// <summary>
- /// Gets or Sets Panel background brush.
- /// </summary>
- public IBrush Background
- {
- get { return GetValue(BackgroundProperty); }
- set { SetValue(BackgroundProperty, value); }
- }
- /// <summary>
- /// Renders the visual to a <see cref="DrawingContext"/>.
- /// </summary>
- /// <param name="context">The drawing context.</param>
- public override void Render(DrawingContext context)
- {
- var background = Background;
- if (background != null)
- {
- var renderSize = Bounds.Size;
- context.FillRectangle(background, new Rect(renderSize));
- }
- base.Render(context);
- }
- /// <summary>
- /// Marks a property on a child as affecting the parent panel's arrangement.
- /// </summary>
- /// <param name="properties">The properties.</param>
- protected static void AffectsParentArrange<TPanel>(params AvaloniaProperty[] properties)
- where TPanel : class, IPanel
- {
- foreach (var property in properties)
- {
- property.Changed.Subscribe(AffectsParentArrangeInvalidate<TPanel>);
- }
- }
- /// <summary>
- /// Marks a property on a child as affecting the parent panel's measurement.
- /// </summary>
- /// <param name="properties">The properties.</param>
- protected static void AffectsParentMeasure<TPanel>(params AvaloniaProperty[] properties)
- where TPanel : class, IPanel
- {
- foreach (var property in properties)
- {
- property.Changed.Subscribe(AffectsParentMeasureInvalidate<TPanel>);
- }
- }
- /// <summary>
- /// Called when the <see cref="Children"/> collection changes.
- /// </summary>
- /// <param name="sender">The event sender.</param>
- /// <param name="e">The event args.</param>
- protected virtual void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
- {
- List<Control> controls;
- switch (e.Action)
- {
- case NotifyCollectionChangedAction.Add:
- controls = e.NewItems.OfType<Control>().ToList();
- LogicalChildren.InsertRange(e.NewStartingIndex, controls);
- VisualChildren.InsertRange(e.NewStartingIndex, e.NewItems.OfType<Visual>());
- break;
- case NotifyCollectionChangedAction.Move:
- LogicalChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex);
- VisualChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex);
- break;
- case NotifyCollectionChangedAction.Remove:
- controls = e.OldItems.OfType<Control>().ToList();
- LogicalChildren.RemoveAll(controls);
- VisualChildren.RemoveAll(e.OldItems.OfType<Visual>());
- break;
- case NotifyCollectionChangedAction.Replace:
- for (var i = 0; i < e.OldItems.Count; ++i)
- {
- var index = i + e.OldStartingIndex;
- var child = (IControl)e.NewItems[i];
- LogicalChildren[index] = child;
- VisualChildren[index] = child;
- }
- break;
- case NotifyCollectionChangedAction.Reset:
- throw new NotSupportedException();
- }
- InvalidateMeasure();
- }
- private static void AffectsParentArrangeInvalidate<TPanel>(AvaloniaPropertyChangedEventArgs e)
- where TPanel : class, IPanel
- {
- var control = e.Sender as IControl;
- var panel = control?.VisualParent as TPanel;
- panel?.InvalidateArrange();
- }
- private static void AffectsParentMeasureInvalidate<TPanel>(AvaloniaPropertyChangedEventArgs e)
- where TPanel : class, IPanel
- {
- var control = e.Sender as IControl;
- var panel = control?.VisualParent as TPanel;
- panel?.InvalidateMeasure();
- }
- }
- }
|