Primary APIs:
LayoutablePanelILayoutManagerLayoutManagerEffectiveViewportChangedEventArgsImportant members:
Layoutable.Measure(...), Arrange(...)Layoutable.MeasureOverride(...), ArrangeOverride(...)Layoutable.InvalidateMeasure(), InvalidateArrange(), UpdateLayout()Layoutable.EffectiveViewportChanged, LayoutUpdatedLayoutable.AffectsMeasure<T>(...), AffectsArrange<T>(...)Panel.ChildrenPanel.AffectsParentMeasure<TPanel>(...), AffectsParentArrange<TPanel>(...)ILayoutManager.InvalidateMeasure(...), InvalidateArrange(...), ExecuteLayoutPass()Reference source files:
src/Avalonia.Base/Layout/Layoutable.cssrc/Avalonia.Controls/Panel.cssrc/Avalonia.Base/Layout/ILayoutManager.cssrc/Avalonia.Base/Layout/LayoutManager.cssrc/Avalonia.Base/Layout/EffectiveViewportChangedEventArgs.csLayoutable lifecycle for custom controls/panels:
DesiredSize (MeasureOverride).ArrangeOverride).InvalidateMeasure/InvalidateArrange).EffectiveViewportChanged.using Avalonia;
using Avalonia.Controls;
public class EqualColumnsPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
if (Children.Count == 0)
return default;
var childWidth = availableSize.Width / Children.Count;
var maxHeight = 0d;
foreach (var child in Children)
{
child.Measure(new Size(childWidth, availableSize.Height));
maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
}
return new Size(availableSize.Width, maxHeight);
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Children.Count == 0)
return finalSize;
var childWidth = finalSize.Width / Children.Count;
for (var i = 0; i < Children.Count; i++)
{
Children[i].Arrange(new Rect(i * childWidth, 0, childWidth, finalSize.Height));
}
return finalSize;
}
}
public class StripePanel : Panel
{
public static readonly StyledProperty<double> StripeWidthProperty =
AvaloniaProperty.Register<StripePanel, double>(nameof(StripeWidth), 24);
static StripePanel()
{
AffectsMeasure<StripePanel>(StripeWidthProperty);
AffectsArrange<StripePanel>(StripeWidthProperty);
}
public double StripeWidth
{
get => GetValue(StripeWidthProperty);
set => SetValue(StripeWidthProperty, value);
}
}
Use Panel.AffectsParentMeasure<TPanel>(...) and AffectsParentArrange<TPanel>(...) when child properties influence parent arrangement logic.
UpdateLayout() in normal control flow.EffectiveViewportChanged.MeasureOverride/ArrangeOverride.InvalidateMeasure() every frame without guard conditions.Default mode:
XAML-first references:
.axamlXAML-first usage example:
<local:EqualColumnsPanel xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.Controls">
<Button Content="A" />
<Button Content="B" />
<Button Content="C" />
</local:EqualColumnsPanel>
Code-only alternative (on request):
var panel = new EqualColumnsPanel();
panel.Children.Add(new Button { Content = "A" });
panel.Children.Add(new Button { Content = "B" });
panel.Children.Add(new Button { Content = "C" });