|
|
@@ -60,6 +60,7 @@ namespace Avalonia.Controls
|
|
|
|
|
|
private class MeasurementCache
|
|
|
{
|
|
|
+
|
|
|
public MeasurementCache(Grid grid)
|
|
|
{
|
|
|
Grid = grid;
|
|
|
@@ -67,19 +68,20 @@ namespace Avalonia.Controls
|
|
|
.Concat(grid.ColumnDefinitions)
|
|
|
.Select(d => new MeasurementResult(d))
|
|
|
.ToList();
|
|
|
+
|
|
|
+ grid.RowDefinitions.
|
|
|
+
|
|
|
}
|
|
|
|
|
|
public void UpdateMeasureResult(GridLayout.MeasureResult rowResult, GridLayout.MeasureResult columnResult)
|
|
|
{
|
|
|
- RowResult = rowResult;
|
|
|
- ColumnResult = columnResult;
|
|
|
MeasurementState = MeasurementState.Cached;
|
|
|
- for (int i = 0; i < rowResult.LengthList.Count; i++)
|
|
|
+ for (int i = 0; i < Grid.RowDefinitions.Count; i++)
|
|
|
{
|
|
|
Results[i].MeasuredResult = rowResult.LengthList[i];
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < columnResult.LengthList.Count; i++)
|
|
|
+ for (int i = 0; i < Grid.ColumnDefinitions.Count; i++)
|
|
|
{
|
|
|
Results[i + rowResult.LengthList.Count].MeasuredResult = columnResult.LengthList[i];
|
|
|
}
|
|
|
@@ -92,8 +94,6 @@ namespace Avalonia.Controls
|
|
|
}
|
|
|
|
|
|
public Grid Grid { get; }
|
|
|
- public GridLayout.MeasureResult RowResult { get; private set; }
|
|
|
- public GridLayout.MeasureResult ColumnResult { get; private set; }
|
|
|
public MeasurementState MeasurementState { get; private set; }
|
|
|
|
|
|
public List<MeasurementResult> Results { get; }
|
|
|
@@ -103,9 +103,9 @@ namespace Avalonia.Controls
|
|
|
|
|
|
private class MeasurementResult
|
|
|
{
|
|
|
- public MeasurementResult(DefinitionBase @base)
|
|
|
+ public MeasurementResult(DefinitionBase definition)
|
|
|
{
|
|
|
- Definition = @base;
|
|
|
+ Definition = definition;
|
|
|
MeasuredResult = double.NaN;
|
|
|
}
|
|
|
|
|
|
@@ -113,22 +113,16 @@ namespace Avalonia.Controls
|
|
|
public double MeasuredResult { get; set; }
|
|
|
}
|
|
|
|
|
|
- private enum ScopeType
|
|
|
- {
|
|
|
- Auto,
|
|
|
- Fixed
|
|
|
- }
|
|
|
-
|
|
|
private class Group
|
|
|
{
|
|
|
public bool IsFixed { get; set; }
|
|
|
|
|
|
- public List<MeasurementResult> Results { get; }
|
|
|
+ public List<MeasurementResult> Results { get; } = new List<MeasurementResult>();
|
|
|
|
|
|
public double CalculatedLength { get; }
|
|
|
}
|
|
|
|
|
|
- private Dictionary<string, Group> _groups = new Dictionary<string, Group>();
|
|
|
+ private readonly Dictionary<string, Group> _groups = new Dictionary<string, Group>();
|
|
|
|
|
|
|
|
|
public SharedSizeScopeHost(Control scope)
|
|
|
@@ -158,57 +152,79 @@ namespace Avalonia.Controls
|
|
|
cache.UpdateMeasureResult(rowResult, columnResult);
|
|
|
}
|
|
|
|
|
|
- internal (GridLayout.MeasureResult, GridLayout.MeasureResult) HandleArrange(Grid grid, GridLayout.MeasureResult rowResult, GridLayout.MeasureResult columnResult)
|
|
|
+ private double Gather(IEnumerable<MeasurementResult> measurements)
|
|
|
{
|
|
|
- var rowConventions = rowResult.LeanLengthList.ToList();
|
|
|
- var rowLengths = rowResult.LengthList.ToList();
|
|
|
- var rowDesiredLength = 0.0;
|
|
|
- for (int i = 0; i < grid.RowDefinitions.Count; i++)
|
|
|
+ var result = 0.0d;
|
|
|
+
|
|
|
+ bool onlyFixed = false;
|
|
|
+
|
|
|
+ foreach (var measurement in measurements)
|
|
|
{
|
|
|
- var definition = grid.RowDefinitions[i];
|
|
|
- if (string.IsNullOrEmpty(definition.SharedSizeGroup))
|
|
|
+ if (measurement.Definition is ColumnDefinition column)
|
|
|
{
|
|
|
- rowDesiredLength += rowResult.LengthList[i];
|
|
|
- continue;
|
|
|
+ if (!onlyFixed && column.Width.IsAbsolute)
|
|
|
+ {
|
|
|
+ onlyFixed = true;
|
|
|
+ result = measurement.MeasuredResult;
|
|
|
+ }
|
|
|
+ else if (onlyFixed == column.Width.IsAbsolute)
|
|
|
+ result = Math.Max(result, measurement.MeasuredResult);
|
|
|
+
|
|
|
+ result = Math.Max(result, column.MinWidth);
|
|
|
}
|
|
|
+ if (measurement.Definition is RowDefinition row)
|
|
|
+ {
|
|
|
+ if (!onlyFixed && row.Height.IsAbsolute)
|
|
|
+ {
|
|
|
+ onlyFixed = true;
|
|
|
+ result = measurement.MeasuredResult;
|
|
|
+ }
|
|
|
+ else if (onlyFixed == row.Height.IsAbsolute)
|
|
|
+ result = Math.Max(result, measurement.MeasuredResult);
|
|
|
+
|
|
|
+ result = Math.Max(result, row.MinHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- var group = _groups[definition.SharedSizeGroup];
|
|
|
-
|
|
|
- var length = group.Results.Max(g => g.MeasuredResult);
|
|
|
- rowConventions[i] = new GridLayout.LengthConvention(
|
|
|
- new GridLength(length),
|
|
|
- rowResult.LeanLengthList[i].MinLength,
|
|
|
- rowResult.LeanLengthList[i].MaxLength
|
|
|
- );
|
|
|
- rowLengths[i] = length;
|
|
|
- rowDesiredLength += length;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
|
|
|
- var columnConventions = columnResult.LeanLengthList.ToList();
|
|
|
- var columnLengths = columnResult.LengthList.ToList();
|
|
|
- var columnDesiredLength = 0.0;
|
|
|
- for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
|
|
|
+ (List<GridLayout.LengthConvention>, List<double>, double) Arrange(IReadOnlyList<DefinitionBase> definitions, GridLayout.MeasureResult measureResult)
|
|
|
+ {
|
|
|
+ var conventions = measureResult.LeanLengthList.ToList();
|
|
|
+ var lengths = measureResult.LengthList.ToList();
|
|
|
+ var desiredLength = 0.0;
|
|
|
+ for (int i = 0; i < definitions.Count; i++)
|
|
|
{
|
|
|
- var definition = grid.ColumnDefinitions[i];
|
|
|
+ var definition = definitions[i];
|
|
|
if (string.IsNullOrEmpty(definition.SharedSizeGroup))
|
|
|
{
|
|
|
- columnDesiredLength += rowResult.LengthList[i];
|
|
|
+ desiredLength += measureResult.LengthList[i];
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
var group = _groups[definition.SharedSizeGroup];
|
|
|
|
|
|
- var length = group.Results.Max(g => g.MeasuredResult);
|
|
|
- columnConventions[i] = new GridLayout.LengthConvention(
|
|
|
+ var length = Gather(group.Results);
|
|
|
+
|
|
|
+ conventions[i] = new GridLayout.LengthConvention(
|
|
|
new GridLength(length),
|
|
|
- columnResult.LeanLengthList[i].MinLength,
|
|
|
- columnResult.LeanLengthList[i].MaxLength
|
|
|
- );
|
|
|
- columnLengths[i] = length;
|
|
|
- columnDesiredLength += length;
|
|
|
+ measureResult.LeanLengthList[i].MinLength,
|
|
|
+ measureResult.LeanLengthList[i].MaxLength
|
|
|
+ );
|
|
|
+ lengths[i] = length;
|
|
|
+ desiredLength += length;
|
|
|
}
|
|
|
|
|
|
+ return (conventions, lengths, desiredLength);
|
|
|
+ }
|
|
|
+
|
|
|
+ internal (GridLayout.MeasureResult, GridLayout.MeasureResult) HandleArrange(Grid grid, GridLayout.MeasureResult rowResult, GridLayout.MeasureResult columnResult)
|
|
|
+ {
|
|
|
+ var (rowConventions, rowLengths, rowDesiredLength) = Arrange(grid.RowDefinitions, rowResult);
|
|
|
+ var (columnConventions, columnLengths, columnDesiredLength) = Arrange(grid.ColumnDefinitions, columnResult);
|
|
|
+
|
|
|
return (
|
|
|
new GridLayout.MeasureResult(
|
|
|
rowResult.ContainerLength,
|
|
|
@@ -231,6 +247,8 @@ namespace Avalonia.Controls
|
|
|
foreach (var result in cache.Results)
|
|
|
{
|
|
|
var scopeName = result.Definition.SharedSizeGroup;
|
|
|
+ if (string.IsNullOrEmpty(scopeName))
|
|
|
+ continue;
|
|
|
if (!_groups.TryGetValue(scopeName, out var group))
|
|
|
_groups.Add(scopeName, group = new Group());
|
|
|
|
|
|
@@ -250,6 +268,8 @@ namespace Avalonia.Controls
|
|
|
foreach (var result in cache.Results)
|
|
|
{
|
|
|
var scopeName = result.Definition.SharedSizeGroup;
|
|
|
+ if (string.IsNullOrEmpty(scopeName))
|
|
|
+ continue;
|
|
|
Debug.Assert(_groups.TryGetValue(scopeName, out var group));
|
|
|
|
|
|
group.Results.Remove(result);
|
|
|
@@ -346,14 +366,14 @@ namespace Avalonia.Controls
|
|
|
if ((bool)arg2.NewValue)
|
|
|
{
|
|
|
Debug.Assert(source.GetValue(s_sharedSizeScopeHostProperty) == null);
|
|
|
- source.SetValue(IsSharedSizeScopeProperty, new SharedSizeScopeHost(source));
|
|
|
+ source.SetValue(s_sharedSizeScopeHostProperty, new SharedSizeScopeHost(source));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var host = source.GetValue(s_sharedSizeScopeHostProperty) as SharedSizeScopeHost;
|
|
|
Debug.Assert(host != null);
|
|
|
host.Dispose();
|
|
|
- source.SetValue(IsSharedSizeScopeProperty, null);
|
|
|
+ source.SetValue(s_sharedSizeScopeHostProperty, null);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -626,11 +646,19 @@ namespace Avalonia.Controls
|
|
|
var columnLayout = _columnLayoutCache;
|
|
|
var rowLayout = _rowLayoutCache;
|
|
|
|
|
|
- var (rowCache, columnCache) = _sharedSizeHost?.HandleArrange(this, _rowMeasureCache, _columnMeasureCache) ?? (_rowMeasureCache, _columnMeasureCache);
|
|
|
+ var (rowCache, columnCache) =
|
|
|
+ _sharedSizeHost?.HandleArrange(this, _rowMeasureCache, _columnMeasureCache) ??
|
|
|
+ (_rowMeasureCache, _columnMeasureCache);
|
|
|
+
|
|
|
+ if (_sharedSizeHost != null)
|
|
|
+ {
|
|
|
+ rowCache = rowLayout.Measure(finalSize.Width, rowCache.LeanLengthList);
|
|
|
+ columnCache = columnLayout.Measure(finalSize.Width, columnCache.LeanLengthList);
|
|
|
+ }
|
|
|
|
|
|
// Calculate for arrange result.
|
|
|
- var columnResult = columnLayout.Arrange(finalSize.Width, rowCache);
|
|
|
- var rowResult = rowLayout.Arrange(finalSize.Height, columnCache);
|
|
|
+ var columnResult = columnLayout.Arrange(finalSize.Width, columnCache);
|
|
|
+ var rowResult = rowLayout.Arrange(finalSize.Height, rowCache);
|
|
|
// Arrange the children.
|
|
|
foreach (var child in Children.OfType<Control>())
|
|
|
{
|