From 160cf4a44a33f5ae691ec23d6f65eba30ab4e784 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Sat, 1 Dec 2018 16:15:54 +0200 Subject: [PATCH] Shared size scope host support in grid ?? --- src/Avalonia.Controls/Grid.cs | 131 +++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index 6e33ac151b..8f5ca73210 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using Avalonia.Collections; +using Avalonia.VisualTree; namespace Avalonia.Controls { @@ -41,10 +42,40 @@ namespace Avalonia.Controls 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; + } + private Segment[,] _rowMatrix; private Segment[,] _colMatrix; @@ -610,6 +641,42 @@ namespace Avalonia.Controls 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(); + + } + } + private void CreateMatrices(int rowCount, int colCount) { if (_rowMatrix == null || _colMatrix == null || @@ -866,11 +933,73 @@ namespace Avalonia.Controls } } + /// + /// 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() { - //TODO: add support for shared size + _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; } + /// /// Stores the layout values of of of . ///