diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj
index 32331d29ab..eabe136791 100644
--- a/src/Avalonia.Controls/Avalonia.Controls.csproj
+++ b/src/Avalonia.Controls/Avalonia.Controls.csproj
@@ -14,4 +14,5 @@
+
diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs
index 98cd5aad02..ad5e96376d 100644
--- a/src/Avalonia.Controls/Grid.cs
+++ b/src/Avalonia.Controls/Grid.cs
@@ -1,601 +1,600 @@
-// // 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.Diagnostics;
-// using System.Linq;
-// using System.Reactive.Linq;
-// using System.Runtime.CompilerServices;
-// using Avalonia.Collections;
-// using Avalonia.Controls.Utils;
-// using Avalonia.VisualTree;
-// using JetBrains.Annotations;
-
-// namespace Avalonia.Controls
-// {
-// ///
-// /// Lays out child controls according to a grid.
-// ///
-// public class Grid : Panel
-// {
-// ///
-// /// Defines the Column attached property.
-// ///
-// public static readonly AttachedProperty ColumnProperty =
-// AvaloniaProperty.RegisterAttached(
-// "Column",
-// validate: ValidateColumn);
-
-// ///
-// /// Defines the ColumnSpan attached property.
-// ///
-// public static readonly AttachedProperty ColumnSpanProperty =
-// AvaloniaProperty.RegisterAttached("ColumnSpan", 1);
-
-// ///
-// /// Defines the Row attached property.
-// ///
-// public static readonly AttachedProperty RowProperty =
-// AvaloniaProperty.RegisterAttached(
-// "Row",
-// validate: ValidateRow);
-
-// ///
-// /// Defines the RowSpan attached property.
-// ///
-// public static readonly AttachedProperty RowSpanProperty =
-// AvaloniaProperty.RegisterAttached("RowSpan", 1);
-
-// public static readonly AttachedProperty IsSharedSizeScopeProperty =
-// AvaloniaProperty.RegisterAttached("IsSharedSizeScope", false);
-
-// protected override void OnMeasureInvalidated()
-// {
-// base.OnMeasureInvalidated();
-// _sharedSizeHost?.InvalidateMeasure(this);
-// }
-
-// private SharedSizeScopeHost _sharedSizeHost;
-
-// ///
-// /// Defines the SharedSizeScopeHost private property.
-// /// The ampersands are used to make accessing the property via xaml inconvenient.
-// ///
-// internal static readonly AttachedProperty s_sharedSizeScopeHostProperty =
-// AvaloniaProperty.RegisterAttached("&&SharedSizeScopeHost");
-
-// private ColumnDefinitions _columnDefinitions;
-
-// private RowDefinitions _rowDefinitions;
-
-// static Grid()
-// {
-// AffectsParentMeasure(ColumnProperty, ColumnSpanProperty, RowProperty, RowSpanProperty);
-// IsSharedSizeScopeProperty.Changed.AddClassHandler(IsSharedSizeScopeChanged);
-// }
-
-// public Grid()
-// {
-// this.AttachedToVisualTree += Grid_AttachedToVisualTree;
-// this.DetachedFromVisualTree += Grid_DetachedFromVisualTree;
-// }
-
-// ///
-// /// Gets or sets the columns definitions for the grid.
-// ///
-// public ColumnDefinitions ColumnDefinitions
-// {
-// get
-// {
-// if (_columnDefinitions == null)
-// {
-// ColumnDefinitions = new ColumnDefinitions();
-// }
-
-// return _columnDefinitions;
-// }
-
-// set
-// {
-// if (_columnDefinitions != null)
-// {
-// throw new NotSupportedException("Reassigning ColumnDefinitions not yet implemented.");
-// }
-
-// _columnDefinitions = value;
-// _columnDefinitions.TrackItemPropertyChanged(_ => InvalidateMeasure());
-// _columnDefinitions.CollectionChanged += (_, __) => InvalidateMeasure();
-// }
-// }
-
-// ///
-// /// Gets or sets the row definitions for the grid.
-// ///
-// public RowDefinitions RowDefinitions
-// {
-// get
-// {
-// if (_rowDefinitions == null)
-// {
-// RowDefinitions = new RowDefinitions();
-// }
-
-// return _rowDefinitions;
-// }
-
-// set
-// {
-// if (_rowDefinitions != null)
-// {
-// throw new NotSupportedException("Reassigning RowDefinitions not yet implemented.");
-// }
-
-// _rowDefinitions = value;
-// _rowDefinitions.TrackItemPropertyChanged(_ => InvalidateMeasure());
-// _rowDefinitions.CollectionChanged += (_, __) => InvalidateMeasure();
-// }
-// }
-
-// ///
-// /// Gets the value of the Column attached property for a control.
-// ///
-// /// The control.
-// /// The control's column.
-// public static int GetColumn(AvaloniaObject element)
-// {
-// return element.GetValue(ColumnProperty);
-// }
-
-// ///
-// /// Gets the value of the ColumnSpan attached property for a control.
-// ///
-// /// The control.
-// /// The control's column span.
-// public static int GetColumnSpan(AvaloniaObject element)
-// {
-// return element.GetValue(ColumnSpanProperty);
-// }
-
-// ///
-// /// Gets the value of the Row attached property for a control.
-// ///
-// /// The control.
-// /// The control's row.
-// public static int GetRow(AvaloniaObject element)
-// {
-// return element.GetValue(RowProperty);
-// }
-
-// ///
-// /// Gets the value of the RowSpan attached property for a control.
-// ///
-// /// The control.
-// /// The control's row span.
-// public static int GetRowSpan(AvaloniaObject element)
-// {
-// return element.GetValue(RowSpanProperty);
-// }
-
-
-// ///
-// /// Gets the value of the IsSharedSizeScope attached property for a control.
-// ///
-// /// The control.
-// /// The control's IsSharedSizeScope value.
-// public static bool GetIsSharedSizeScope(AvaloniaObject element)
-// {
-// return element.GetValue(IsSharedSizeScopeProperty);
-// }
-
-// ///
-// /// Sets the value of the Column attached property for a control.
-// ///
-// /// The control.
-// /// The column value.
-// public static void SetColumn(AvaloniaObject element, int value)
-// {
-// element.SetValue(ColumnProperty, value);
-// }
-
-// ///
-// /// Sets the value of the ColumnSpan attached property for a control.
-// ///
-// /// The control.
-// /// The column span value.
-// public static void SetColumnSpan(AvaloniaObject element, int value)
-// {
-// element.SetValue(ColumnSpanProperty, value);
-// }
-
-// ///
-// /// Sets the value of the Row attached property for a control.
-// ///
-// /// The control.
-// /// The row value.
-// public static void SetRow(AvaloniaObject element, int value)
-// {
-// element.SetValue(RowProperty, value);
-// }
-
-// ///
-// /// Sets the value of the RowSpan attached property for a control.
-// ///
-// /// The control.
-// /// The row span value.
-// public static void SetRowSpan(AvaloniaObject element, int value)
-// {
-// element.SetValue(RowSpanProperty, value);
-// }
-
-// ///
-// /// Sets the value of IsSharedSizeScope property for a control.
-// ///
-// /// The control.
-// /// The IsSharedSizeScope value.
-// public static void SetIsSharedSizeScope(AvaloniaObject element, bool value)
-// {
-// element.SetValue(IsSharedSizeScopeProperty, value);
-// }
-
-// ///
-// /// Gets the result of the last column measurement.
-// /// Use this result to reduce the arrange calculation.
-// ///
-// private GridLayout.MeasureResult _columnMeasureCache;
-
-// ///
-// /// Gets the result of the last row measurement.
-// /// Use this result to reduce the arrange calculation.
-// ///
-// private GridLayout.MeasureResult _rowMeasureCache;
-
-// ///
-// /// Gets the row layout as of the last measure.
-// ///
-// private GridLayout _rowLayoutCache;
-
-// ///
-// /// Gets the column layout as of the last measure.
-// ///
-// private GridLayout _columnLayoutCache;
-
-// ///
-// /// Measures the grid.
-// ///
-// /// The available size.
-// /// The desired size of the control.
-// protected override Size MeasureOverride(Size constraint)
-// {
-// // Situation 1/2:
-// // If the grid doesn't have any column/row definitions, it behaves like a normal panel.
-// // GridLayout supports this situation but we handle this separately for performance.
-
-// if (ColumnDefinitions.Count == 0 && RowDefinitions.Count == 0)
-// {
-// var maxWidth = 0.0;
-// var maxHeight = 0.0;
-// foreach (var child in Children.OfType())
-// {
-// child.Measure(constraint);
-// maxWidth = Math.Max(maxWidth, child.DesiredSize.Width);
-// maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
-// }
-
-// maxWidth = Math.Min(maxWidth, constraint.Width);
-// maxHeight = Math.Min(maxHeight, constraint.Height);
-// return new Size(maxWidth, maxHeight);
-// }
-
-// // Situation 2/2:
-// // If the grid defines some columns or rows.
-// // Debug Tip:
-// // - GridLayout doesn't hold any state, so you can drag the debugger execution
-// // arrow back to any statements and re-run them without any side-effect.
-
-// var measureCache = new Dictionary();
-// var (safeColumns, safeRows) = GetSafeColumnRows();
-// var columnLayout = new GridLayout(ColumnDefinitions);
-// var rowLayout = new GridLayout(RowDefinitions);
-// // Note: If a child stays in a * or Auto column/row, use constraint to measure it.
-// columnLayout.AppendMeasureConventions(safeColumns, child => MeasureOnce(child, constraint).Width);
-// rowLayout.AppendMeasureConventions(safeRows, child => MeasureOnce(child, constraint).Height);
-
-// // Calculate measurement.
-// var columnResult = columnLayout.Measure(constraint.Width);
-// var rowResult = rowLayout.Measure(constraint.Height);
-
-// // Use the results of the measurement to measure the rest of the children.
-// foreach (var child in Children.OfType())
-// {
-// var (column, columnSpan) = safeColumns[child];
-// var (row, rowSpan) = safeRows[child];
-// var width = Enumerable.Range(column, columnSpan).Select(x => columnResult.LengthList[x]).Sum();
-// var height = Enumerable.Range(row, rowSpan).Select(x => rowResult.LengthList[x]).Sum();
-
-// MeasureOnce(child, new Size(width, height));
-// }
-
-// // Cache the measure result and return the desired size.
-// _columnMeasureCache = columnResult;
-// _rowMeasureCache = rowResult;
-// _rowLayoutCache = rowLayout;
-// _columnLayoutCache = columnLayout;
-
-// if (_sharedSizeHost?.ParticipatesInScope(this) ?? false)
-// {
-// _sharedSizeHost.UpdateMeasureStatus(this, rowResult, columnResult);
-// }
-
-// return new Size(columnResult.DesiredLength, rowResult.DesiredLength);
-
-// // Measure each child only once.
-// // If a child has been measured, it will just return the desired size.
-// Size MeasureOnce(Control child, Size size)
-// {
-// if (measureCache.TryGetValue(child, out var desiredSize))
-// {
-// return desiredSize;
-// }
-
-// child.Measure(size);
-// desiredSize = child.DesiredSize;
-// measureCache[child] = desiredSize;
-// return desiredSize;
-// }
-// }
-
-// ///
-// /// Arranges the grid's children.
-// ///
-// /// The size allocated to the control.
-// /// The space taken.
-// protected override Size ArrangeOverride(Size finalSize)
-// {
-// // Situation 1/2:
-// // If the grid doesn't have any column/row definitions, it behaves like a normal panel.
-// // GridLayout supports this situation but we handle this separately for performance.
-
-// if (ColumnDefinitions.Count == 0 && RowDefinitions.Count == 0)
-// {
-// foreach (var child in Children.OfType())
-// {
-// child.Arrange(new Rect(finalSize));
-// }
-
-// return finalSize;
-// }
-
-// // Situation 2/2:
-// // If the grid defines some columns or rows.
-// // Debug Tip:
-// // - GridLayout doesn't hold any state, so you can drag the debugger execution
-// // arrow back to any statements and re-run them without any side-effect.
-
-// var (safeColumns, safeRows) = GetSafeColumnRows();
-// var columnLayout = _columnLayoutCache;
-// var rowLayout = _rowLayoutCache;
-
-// var rowCache = _rowMeasureCache;
-// var columnCache = _columnMeasureCache;
-
-// if (_sharedSizeHost?.ParticipatesInScope(this) ?? false)
-// {
-// (rowCache, columnCache) = _sharedSizeHost.HandleArrange(this, _rowMeasureCache, _columnMeasureCache);
+// 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.Diagnostics;
+using System.Linq;
+using System.Reactive.Linq;
+using System.Runtime.CompilerServices;
+using Avalonia.Collections;
+using Avalonia.Controls.Utils;
+using Avalonia.VisualTree;
+using JetBrains.Annotations;
+
+namespace Avalonia.Controls
+{
+ ///
+ /// Lays out child controls according to a grid.
+ ///
+ public class Grid : Panel
+ {
+ ///
+ /// Defines the Column attached property.
+ ///
+ public static readonly AttachedProperty ColumnProperty =
+ AvaloniaProperty.RegisterAttached(
+ "Column",
+ validate: ValidateColumn);
+
+ ///
+ /// Defines the ColumnSpan attached property.
+ ///
+ public static readonly AttachedProperty ColumnSpanProperty =
+ AvaloniaProperty.RegisterAttached("ColumnSpan", 1);
+
+ ///
+ /// Defines the Row attached property.
+ ///
+ public static readonly AttachedProperty RowProperty =
+ AvaloniaProperty.RegisterAttached(
+ "Row",
+ validate: ValidateRow);
+
+ ///
+ /// Defines the RowSpan attached property.
+ ///
+ public static readonly AttachedProperty RowSpanProperty =
+ AvaloniaProperty.RegisterAttached("RowSpan", 1);
+
+ public static readonly AttachedProperty IsSharedSizeScopeProperty =
+ AvaloniaProperty.RegisterAttached("IsSharedSizeScope", false);
+
+ protected override void OnMeasureInvalidated()
+ {
+ base.OnMeasureInvalidated();
+ _sharedSizeHost?.InvalidateMeasure(this);
+ }
+
+ private SharedSizeScopeHost _sharedSizeHost;
+
+ ///
+ /// Defines the SharedSizeScopeHost private property.
+ /// The ampersands are used to make accessing the property via xaml inconvenient.
+ ///
+ internal static readonly AttachedProperty s_sharedSizeScopeHostProperty =
+ AvaloniaProperty.RegisterAttached("&&SharedSizeScopeHost");
+
+ private ColumnDefinitions _columnDefinitions;
+
+ private RowDefinitions _rowDefinitions;
+
+ static Grid()
+ {
+ AffectsParentMeasure(ColumnProperty, ColumnSpanProperty, RowProperty, RowSpanProperty);
+ IsSharedSizeScopeProperty.Changed.AddClassHandler(IsSharedSizeScopeChanged);
+ }
+
+ public Grid()
+ {
+ this.AttachedToVisualTree += Grid_AttachedToVisualTree;
+ this.DetachedFromVisualTree += Grid_DetachedFromVisualTree;
+ }
+
+ ///
+ /// Gets or sets the columns definitions for the grid.
+ ///
+ public ColumnDefinitions ColumnDefinitions
+ {
+ get
+ {
+ if (_columnDefinitions == null)
+ {
+ ColumnDefinitions = new ColumnDefinitions();
+ }
+
+ return _columnDefinitions;
+ }
+
+ set
+ {
+ if (_columnDefinitions != null)
+ {
+ throw new NotSupportedException("Reassigning ColumnDefinitions not yet implemented.");
+ }
+
+ _columnDefinitions = value;
+ _columnDefinitions.TrackItemPropertyChanged(_ => InvalidateMeasure());
+ _columnDefinitions.CollectionChanged += (_, __) => InvalidateMeasure();
+ }
+ }
+
+ ///
+ /// Gets or sets the row definitions for the grid.
+ ///
+ public RowDefinitions RowDefinitions
+ {
+ get
+ {
+ if (_rowDefinitions == null)
+ {
+ RowDefinitions = new RowDefinitions();
+ }
+
+ return _rowDefinitions;
+ }
+
+ set
+ {
+ if (_rowDefinitions != null)
+ {
+ throw new NotSupportedException("Reassigning RowDefinitions not yet implemented.");
+ }
+
+ _rowDefinitions = value;
+ _rowDefinitions.TrackItemPropertyChanged(_ => InvalidateMeasure());
+ _rowDefinitions.CollectionChanged += (_, __) => InvalidateMeasure();
+ }
+ }
+
+ ///
+ /// Gets the value of the Column attached property for a control.
+ ///
+ /// The control.
+ /// The control's column.
+ public static int GetColumn(AvaloniaObject element)
+ {
+ return element.GetValue(ColumnProperty);
+ }
+
+ ///
+ /// Gets the value of the ColumnSpan attached property for a control.
+ ///
+ /// The control.
+ /// The control's column span.
+ public static int GetColumnSpan(AvaloniaObject element)
+ {
+ return element.GetValue(ColumnSpanProperty);
+ }
+
+ ///
+ /// Gets the value of the Row attached property for a control.
+ ///
+ /// The control.
+ /// The control's row.
+ public static int GetRow(AvaloniaObject element)
+ {
+ return element.GetValue(RowProperty);
+ }
+
+ ///
+ /// Gets the value of the RowSpan attached property for a control.
+ ///
+ /// The control.
+ /// The control's row span.
+ public static int GetRowSpan(AvaloniaObject element)
+ {
+ return element.GetValue(RowSpanProperty);
+ }
+
+
+ ///
+ /// Gets the value of the IsSharedSizeScope attached property for a control.
+ ///
+ /// The control.
+ /// The control's IsSharedSizeScope value.
+ public static bool GetIsSharedSizeScope(AvaloniaObject element)
+ {
+ return element.GetValue(IsSharedSizeScopeProperty);
+ }
+
+ ///
+ /// Sets the value of the Column attached property for a control.
+ ///
+ /// The control.
+ /// The column value.
+ public static void SetColumn(AvaloniaObject element, int value)
+ {
+ element.SetValue(ColumnProperty, value);
+ }
+
+ ///
+ /// Sets the value of the ColumnSpan attached property for a control.
+ ///
+ /// The control.
+ /// The column span value.
+ public static void SetColumnSpan(AvaloniaObject element, int value)
+ {
+ element.SetValue(ColumnSpanProperty, value);
+ }
+
+ ///
+ /// Sets the value of the Row attached property for a control.
+ ///
+ /// The control.
+ /// The row value.
+ public static void SetRow(AvaloniaObject element, int value)
+ {
+ element.SetValue(RowProperty, value);
+ }
+
+ ///
+ /// Sets the value of the RowSpan attached property for a control.
+ ///
+ /// The control.
+ /// The row span value.
+ public static void SetRowSpan(AvaloniaObject element, int value)
+ {
+ element.SetValue(RowSpanProperty, value);
+ }
+
+ ///
+ /// Sets the value of IsSharedSizeScope property for a control.
+ ///
+ /// The control.
+ /// The IsSharedSizeScope value.
+ public static void SetIsSharedSizeScope(AvaloniaObject element, bool value)
+ {
+ element.SetValue(IsSharedSizeScopeProperty, value);
+ }
+
+ ///
+ /// Gets the result of the last column measurement.
+ /// Use this result to reduce the arrange calculation.
+ ///
+ private GridLayout.MeasureResult _columnMeasureCache;
+
+ ///
+ /// Gets the result of the last row measurement.
+ /// Use this result to reduce the arrange calculation.
+ ///
+ private GridLayout.MeasureResult _rowMeasureCache;
+
+ ///
+ /// Gets the row layout as of the last measure.
+ ///
+ private GridLayout _rowLayoutCache;
+
+ ///
+ /// Gets the column layout as of the last measure.
+ ///
+ private GridLayout _columnLayoutCache;
+
+ ///
+ /// Measures the grid.
+ ///
+ /// The available size.
+ /// The desired size of the control.
+ protected override Size MeasureOverride(Size constraint)
+ {
+ // Situation 1/2:
+ // If the grid doesn't have any column/row definitions, it behaves like a normal panel.
+ // GridLayout supports this situation but we handle this separately for performance.
+
+ if (ColumnDefinitions.Count == 0 && RowDefinitions.Count == 0)
+ {
+ var maxWidth = 0.0;
+ var maxHeight = 0.0;
+ foreach (var child in Children.OfType())
+ {
+ child.Measure(constraint);
+ maxWidth = Math.Max(maxWidth, child.DesiredSize.Width);
+ maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
+ }
+
+ maxWidth = Math.Min(maxWidth, constraint.Width);
+ maxHeight = Math.Min(maxHeight, constraint.Height);
+ return new Size(maxWidth, maxHeight);
+ }
+
+ // Situation 2/2:
+ // If the grid defines some columns or rows.
+ // Debug Tip:
+ // - GridLayout doesn't hold any state, so you can drag the debugger execution
+ // arrow back to any statements and re-run them without any side-effect.
+
+ var measureCache = new Dictionary();
+ var (safeColumns, safeRows) = GetSafeColumnRows();
+ var columnLayout = new GridLayout(ColumnDefinitions);
+ var rowLayout = new GridLayout(RowDefinitions);
+ // Note: If a child stays in a * or Auto column/row, use constraint to measure it.
+ columnLayout.AppendMeasureConventions(safeColumns, child => MeasureOnce(child, constraint).Width);
+ rowLayout.AppendMeasureConventions(safeRows, child => MeasureOnce(child, constraint).Height);
+
+ // Calculate measurement.
+ var columnResult = columnLayout.Measure(constraint.Width);
+ var rowResult = rowLayout.Measure(constraint.Height);
+
+ // Use the results of the measurement to measure the rest of the children.
+ foreach (var child in Children.OfType())
+ {
+ var (column, columnSpan) = safeColumns[child];
+ var (row, rowSpan) = safeRows[child];
+ var width = Enumerable.Range(column, columnSpan).Select(x => columnResult.LengthList[x]).Sum();
+ var height = Enumerable.Range(row, rowSpan).Select(x => rowResult.LengthList[x]).Sum();
+
+ MeasureOnce(child, new Size(width, height));
+ }
+
+ // Cache the measure result and return the desired size.
+ _columnMeasureCache = columnResult;
+ _rowMeasureCache = rowResult;
+ _rowLayoutCache = rowLayout;
+ _columnLayoutCache = columnLayout;
+
+ if (_sharedSizeHost?.ParticipatesInScope(this) ?? false)
+ {
+ _sharedSizeHost.UpdateMeasureStatus(this, rowResult, columnResult);
+ }
+
+ return new Size(columnResult.DesiredLength, rowResult.DesiredLength);
+
+ // Measure each child only once.
+ // If a child has been measured, it will just return the desired size.
+ Size MeasureOnce(Control child, Size size)
+ {
+ if (measureCache.TryGetValue(child, out var desiredSize))
+ {
+ return desiredSize;
+ }
+
+ child.Measure(size);
+ desiredSize = child.DesiredSize;
+ measureCache[child] = desiredSize;
+ return desiredSize;
+ }
+ }
+
+ ///
+ /// Arranges the grid's children.
+ ///
+ /// The size allocated to the control.
+ /// The space taken.
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ // Situation 1/2:
+ // If the grid doesn't have any column/row definitions, it behaves like a normal panel.
+ // GridLayout supports this situation but we handle this separately for performance.
+
+ if (ColumnDefinitions.Count == 0 && RowDefinitions.Count == 0)
+ {
+ foreach (var child in Children.OfType())
+ {
+ child.Arrange(new Rect(finalSize));
+ }
+
+ return finalSize;
+ }
+
+ // Situation 2/2:
+ // If the grid defines some columns or rows.
+ // Debug Tip:
+ // - GridLayout doesn't hold any state, so you can drag the debugger execution
+ // arrow back to any statements and re-run them without any side-effect.
+
+ var (safeColumns, safeRows) = GetSafeColumnRows();
+ var columnLayout = _columnLayoutCache;
+ var rowLayout = _rowLayoutCache;
+
+ var rowCache = _rowMeasureCache;
+ var columnCache = _columnMeasureCache;
+
+ if (_sharedSizeHost?.ParticipatesInScope(this) ?? false)
+ {
+ (rowCache, columnCache) = _sharedSizeHost.HandleArrange(this, _rowMeasureCache, _columnMeasureCache);
-// rowCache = rowLayout.Measure(finalSize.Height, rowCache.LeanLengthList);
-// columnCache = columnLayout.Measure(finalSize.Width, columnCache.LeanLengthList);
-// }
-
-// // Calculate for arrange result.
-// var columnResult = columnLayout.Arrange(finalSize.Width, columnCache);
-// var rowResult = rowLayout.Arrange(finalSize.Height, rowCache);
-// // Arrange the children.
-// foreach (var child in Children.OfType())
-// {
-// var (column, columnSpan) = safeColumns[child];
-// var (row, rowSpan) = safeRows[child];
-// var x = Enumerable.Range(0, column).Sum(c => columnResult.LengthList[c]);
-// var y = Enumerable.Range(0, row).Sum(r => rowResult.LengthList[r]);
-// var width = Enumerable.Range(column, columnSpan).Sum(c => columnResult.LengthList[c]);
-// var height = Enumerable.Range(row, rowSpan).Sum(r => rowResult.LengthList[r]);
-// child.Arrange(new Rect(x, y, width, height));
-// }
-
-// // Assign the actual width.
-// for (var i = 0; i < ColumnDefinitions.Count; i++)
-// {
-// ColumnDefinitions[i].ActualWidth = columnResult.LengthList[i];
-// }
-
-// // Assign the actual height.
-// for (var i = 0; i < RowDefinitions.Count; i++)
-// {
-// RowDefinitions[i].ActualHeight = rowResult.LengthList[i];
-// }
-
-// // Return the render size.
-// return finalSize;
-// }
-
-// ///
-// /// Tests whether this grid belongs to a shared size scope.
-// ///
-// /// True if the grid is registered in a shared size scope.
-// internal bool HasSharedSizeScope()
-// {
-// return _sharedSizeHost != null;
-// }
-
-// ///
-// /// Called when the SharedSizeScope for a given grid has changed.
-// /// Unregisters the grid from it's current scope and finds a new one (if any)
-// ///
-// ///
-// /// This method, while not efficient, correctly handles nested scopes, with any order of scope changes.
-// ///
-// internal void SharedScopeChanged()
-// {
-// _sharedSizeHost?.UnegisterGrid(this);
-
-// _sharedSizeHost = null;
-// var scope = this.GetVisualAncestors().OfType()
-// .FirstOrDefault(c => c.GetValue(IsSharedSizeScopeProperty));
-
-// if (scope != null)
-// {
-// _sharedSizeHost = scope.GetValue(s_sharedSizeScopeHostProperty);
-// _sharedSizeHost.RegisterGrid(this);
-// }
-
-// InvalidateMeasure();
-// }
-
-// ///
-// /// Callback when a grid is attached to the visual tree. Finds the innermost SharedSizeScope and registers the grid
-// /// in it.
-// ///
-// /// The source of the event.
-// /// The event arguments.
-// private void Grid_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
-// {
-// var scope =
-// new Control[] { this }.Concat(this.GetVisualAncestors().OfType())
-// .FirstOrDefault(c => c.GetValue(IsSharedSizeScopeProperty));
-
-// if (_sharedSizeHost != null)
-// throw new AvaloniaInternalException("Shared size scope already present when attaching to visual tree!");
-
-// if (scope != null)
-// {
-// _sharedSizeHost = scope.GetValue(s_sharedSizeScopeHostProperty);
-// _sharedSizeHost.RegisterGrid(this);
-// }
-// }
-
-// ///
-// /// Callback when a grid is detached from the visual tree. Unregisters the grid from its SharedSizeScope if any.
-// ///
-// /// The source of the event.
-// /// The event arguments.
-// private void Grid_DetachedFromVisualTree(object sender, VisualTreeAttachmentEventArgs e)
-// {
-// _sharedSizeHost?.UnegisterGrid(this);
-// _sharedSizeHost = null;
-// }
-
-
-// ///
-// /// Get the safe column/columnspan and safe row/rowspan.
-// /// This method ensures that none of the children has a column/row outside the bounds of the definitions.
-// ///
-// [Pure]
-// private (Dictionary safeColumns,
-// Dictionary safeRows) GetSafeColumnRows()
-// {
-// var columnCount = ColumnDefinitions.Count;
-// var rowCount = RowDefinitions.Count;
-// columnCount = columnCount == 0 ? 1 : columnCount;
-// rowCount = rowCount == 0 ? 1 : rowCount;
-// var safeColumns = Children.OfType().ToDictionary(child => child,
-// child => GetSafeSpan(columnCount, GetColumn(child), GetColumnSpan(child)));
-// var safeRows = Children.OfType().ToDictionary(child => child,
-// child => GetSafeSpan(rowCount, GetRow(child), GetRowSpan(child)));
-// return (safeColumns, safeRows);
-// }
-
-// ///
-// /// Gets the safe row/column and rowspan/columnspan for a specified range.
-// /// The user may assign row/column properties outside the bounds of the row/column count, this method coerces them inside.
-// ///
-// /// The row or column count.
-// /// The row or column that the user assigned.
-// /// The rowspan or columnspan that the user assigned.
-// /// The safe row/column and rowspan/columnspan.
-// [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)]
-// private static (int index, int span) GetSafeSpan(int length, int userIndex, int userSpan)
-// {
-// var index = userIndex;
-// var span = userSpan;
-
-// if (index < 0)
-// {
-// span = index + span;
-// index = 0;
-// }
-
-// if (span <= 0)
-// {
-// span = 1;
-// }
-
-// if (userIndex >= length)
-// {
-// index = length - 1;
-// span = 1;
-// }
-// else if (userIndex + userSpan > length)
-// {
-// span = length - userIndex;
-// }
-
-// return (index, span);
-// }
-
-// private static int ValidateColumn(AvaloniaObject o, int value)
-// {
-// if (value < 0)
-// {
-// throw new ArgumentException("Invalid Grid.Column value.");
-// }
-
-// return value;
-// }
-
-// private static int ValidateRow(AvaloniaObject o, int value)
-// {
-// if (value < 0)
-// {
-// throw new ArgumentException("Invalid Grid.Row value.");
-// }
-
-// return value;
-// }
-
-// ///
-// /// Called when the value of changes for a control.
-// ///
-// /// The control that triggered the change.
-// /// Change arguments.
-// private static void IsSharedSizeScopeChanged(Control source, AvaloniaPropertyChangedEventArgs arg2)
-// {
-// var shouldDispose = (arg2.OldValue is bool d) && d;
-// if (shouldDispose)
-// {
-// var host = source.GetValue(s_sharedSizeScopeHostProperty) as SharedSizeScopeHost;
-// if (host == null)
-// throw new AvaloniaInternalException("SharedScopeHost wasn't set when IsSharedSizeScope was true!");
-// host.Dispose();
-// source.ClearValue(s_sharedSizeScopeHostProperty);
-// }
-
-// var shouldAssign = (arg2.NewValue is bool a) && a;
-// if (shouldAssign)
-// {
-// if (source.GetValue(s_sharedSizeScopeHostProperty) != null)
-// throw new AvaloniaInternalException("SharedScopeHost was already set when IsSharedSizeScope is only now being set to true!");
-// source.SetValue(s_sharedSizeScopeHostProperty, new SharedSizeScopeHost());
-// }
-
-// // if the scope has changed, notify the descendant grids that they need to update.
-// if (source.GetVisualRoot() != null && shouldAssign || shouldDispose)
-// {
-// var participatingGrids = new[] { source }.Concat(source.GetVisualDescendants()).OfType();
-
-// foreach (var grid in participatingGrids)
-// grid.SharedScopeChanged();
-
-// }
-// }
-// }
-// }
+ rowCache = rowLayout.Measure(finalSize.Height, rowCache.LeanLengthList);
+ columnCache = columnLayout.Measure(finalSize.Width, columnCache.LeanLengthList);
+ }
+
+ // Calculate for arrange result.
+ var columnResult = columnLayout.Arrange(finalSize.Width, columnCache);
+ var rowResult = rowLayout.Arrange(finalSize.Height, rowCache);
+ // Arrange the children.
+ foreach (var child in Children.OfType())
+ {
+ var (column, columnSpan) = safeColumns[child];
+ var (row, rowSpan) = safeRows[child];
+ var x = Enumerable.Range(0, column).Sum(c => columnResult.LengthList[c]);
+ var y = Enumerable.Range(0, row).Sum(r => rowResult.LengthList[r]);
+ var width = Enumerable.Range(column, columnSpan).Sum(c => columnResult.LengthList[c]);
+ var height = Enumerable.Range(row, rowSpan).Sum(r => rowResult.LengthList[r]);
+ child.Arrange(new Rect(x, y, width, height));
+ }
+
+ // Assign the actual width.
+ for (var i = 0; i < ColumnDefinitions.Count; i++)
+ {
+ ColumnDefinitions[i].ActualWidth = columnResult.LengthList[i];
+ }
+
+ // Assign the actual height.
+ for (var i = 0; i < RowDefinitions.Count; i++)
+ {
+ RowDefinitions[i].ActualHeight = rowResult.LengthList[i];
+ }
+
+ // Return the render size.
+ return finalSize;
+ }
+
+ ///
+ /// Tests whether this grid belongs to a shared size scope.
+ ///
+ /// True if the grid is registered in a shared size scope.
+ internal bool HasSharedSizeScope()
+ {
+ return _sharedSizeHost != null;
+ }
+
+ ///
+ /// Called when the SharedSizeScope for a given grid has changed.
+ /// Unregisters the grid from it's current scope and finds a new one (if any)
+ ///
+ ///
+ /// This method, while not efficient, correctly handles nested scopes, with any order of scope changes.
+ ///
+ internal void SharedScopeChanged()
+ {
+ _sharedSizeHost?.UnegisterGrid(this);
+
+ _sharedSizeHost = null;
+ var scope = this.GetVisualAncestors().OfType()
+ .FirstOrDefault(c => c.GetValue(IsSharedSizeScopeProperty));
+
+ if (scope != null)
+ {
+ _sharedSizeHost = scope.GetValue(s_sharedSizeScopeHostProperty);
+ _sharedSizeHost.RegisterGrid(this);
+ }
+
+ InvalidateMeasure();
+ }
+
+ ///
+ /// Callback when a grid is attached to the visual tree. Finds the innermost SharedSizeScope and registers the grid
+ /// in it.
+ ///
+ /// The source of the event.
+ /// The event arguments.
+ private void Grid_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
+ {
+ var scope =
+ new Control[] { this }.Concat(this.GetVisualAncestors().OfType())
+ .FirstOrDefault(c => c.GetValue(IsSharedSizeScopeProperty));
+
+ if (_sharedSizeHost != null)
+ throw new AvaloniaInternalException("Shared size scope already present when attaching to visual tree!");
+
+ if (scope != null)
+ {
+ _sharedSizeHost = scope.GetValue(s_sharedSizeScopeHostProperty);
+ _sharedSizeHost.RegisterGrid(this);
+ }
+ }
+
+ ///
+ /// Callback when a grid is detached from the visual tree. Unregisters the grid from its SharedSizeScope if any.
+ ///
+ /// The source of the event.
+ /// The event arguments.
+ private void Grid_DetachedFromVisualTree(object sender, VisualTreeAttachmentEventArgs e)
+ {
+ _sharedSizeHost?.UnegisterGrid(this);
+ _sharedSizeHost = null;
+ }
+
+
+ ///
+ /// Get the safe column/columnspan and safe row/rowspan.
+ /// This method ensures that none of the children has a column/row outside the bounds of the definitions.
+ ///
+ [Pure]
+ private (Dictionary safeColumns,
+ Dictionary safeRows) GetSafeColumnRows()
+ {
+ var columnCount = ColumnDefinitions.Count;
+ var rowCount = RowDefinitions.Count;
+ columnCount = columnCount == 0 ? 1 : columnCount;
+ rowCount = rowCount == 0 ? 1 : rowCount;
+ var safeColumns = Children.OfType().ToDictionary(child => child,
+ child => GetSafeSpan(columnCount, GetColumn(child), GetColumnSpan(child)));
+ var safeRows = Children.OfType().ToDictionary(child => child,
+ child => GetSafeSpan(rowCount, GetRow(child), GetRowSpan(child)));
+ return (safeColumns, safeRows);
+ }
+
+ ///
+ /// Gets the safe row/column and rowspan/columnspan for a specified range.
+ /// The user may assign row/column properties outside the bounds of the row/column count, this method coerces them inside.
+ ///
+ /// The row or column count.
+ /// The row or column that the user assigned.
+ /// The rowspan or columnspan that the user assigned.
+ /// The safe row/column and rowspan/columnspan.
+ [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static (int index, int span) GetSafeSpan(int length, int userIndex, int userSpan)
+ {
+ var index = userIndex;
+ var span = userSpan;
+
+ if (index < 0)
+ {
+ span = index + span;
+ index = 0;
+ }
+
+ if (span <= 0)
+ {
+ span = 1;
+ }
+
+ if (userIndex >= length)
+ {
+ index = length - 1;
+ span = 1;
+ }
+ else if (userIndex + userSpan > length)
+ {
+ span = length - userIndex;
+ }
+
+ return (index, span);
+ }
+
+ private static int ValidateColumn(AvaloniaObject o, int value)
+ {
+ if (value < 0)
+ {
+ throw new ArgumentException("Invalid Grid.Column value.");
+ }
+
+ return value;
+ }
+
+ private static int ValidateRow(AvaloniaObject o, int value)
+ {
+ if (value < 0)
+ {
+ throw new ArgumentException("Invalid Grid.Row value.");
+ }
+
+ return value;
+ }
+
+ ///
+ /// Called when the value of changes for a control.
+ ///
+ /// The control that triggered the change.
+ /// Change arguments.
+ private static void IsSharedSizeScopeChanged(Control source, AvaloniaPropertyChangedEventArgs arg2)
+ {
+ var shouldDispose = (arg2.OldValue is bool d) && d;
+ if (shouldDispose)
+ {
+ var host = source.GetValue(s_sharedSizeScopeHostProperty) as SharedSizeScopeHost;
+ if (host == null)
+ throw new AvaloniaInternalException("SharedScopeHost wasn't set when IsSharedSizeScope was true!");
+ host.Dispose();
+ source.ClearValue(s_sharedSizeScopeHostProperty);
+ }
+
+ var shouldAssign = (arg2.NewValue is bool a) && a;
+ if (shouldAssign)
+ {
+ if (source.GetValue(s_sharedSizeScopeHostProperty) != null)
+ throw new AvaloniaInternalException("SharedScopeHost was already set when IsSharedSizeScope is only now being set to true!");
+ source.SetValue(s_sharedSizeScopeHostProperty, new SharedSizeScopeHost());
+ }
+
+ // if the scope has changed, notify the descendant grids that they need to update.
+ if (source.GetVisualRoot() != null && shouldAssign || shouldDispose)
+ {
+ var participatingGrids = new[] { source }.Concat(source.GetVisualDescendants()).OfType();
+
+ foreach (var grid in participatingGrids)
+ grid.SharedScopeChanged();
+ }
+ }
+ }
+}