|
|
|
@ -9,27 +9,16 @@ using Avalonia.Utilities; |
|
|
|
|
|
|
|
namespace Avalonia.Controls |
|
|
|
{ |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Base class for <see cref="ColumnDefinition"/> and <see cref="RowDefinition"/>.
|
|
|
|
/// </summary>
|
|
|
|
public abstract class DefinitionBase : ContentControl |
|
|
|
public abstract class DefinitionBase : AvaloniaObject |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Static ctor. Used for static registration of properties.
|
|
|
|
/// </summary>
|
|
|
|
static DefinitionBase() |
|
|
|
{ |
|
|
|
SharedSizeGroupProperty.Changed.AddClassHandler<DefinitionBase>(OnSharedSizeGroupPropertyChanged); |
|
|
|
// BoundsProperty.Changed.AddClassHandler<DefinitionBase>(OnUserSizePropertyChanged);
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Defines the <see cref="SharedSizeGroup"/> property.
|
|
|
|
/// </summary>
|
|
|
|
public static readonly StyledProperty<string> SharedSizeGroupProperty = |
|
|
|
AvaloniaProperty.Register<DefinitionBase, string>(nameof(SharedSizeGroup), inherits: true, validate: SharedSizeGroupPropertyValueValid); |
|
|
|
AvaloniaProperty.Register<DefinitionBase, string>(nameof(SharedSizeGroup), inherits: true); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the name of the shared size group of the column or row.
|
|
|
|
@ -41,84 +30,30 @@ namespace Avalonia.Controls |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Performs action preparing definition to enter layout calculation mode.
|
|
|
|
/// </summary>
|
|
|
|
internal void OnBeforeLayout(Grid grid) |
|
|
|
{ |
|
|
|
// reset layout state.
|
|
|
|
_minSize = 0; |
|
|
|
LayoutWasUpdated = true; |
|
|
|
|
|
|
|
// defer verification for shared definitions
|
|
|
|
if (_sharedState != null) { _sharedState.EnsureDeferredValidation(grid); } |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns <c>true</c> if this definition is a part of shared group.
|
|
|
|
/// </summary>
|
|
|
|
internal bool IsShared |
|
|
|
{ |
|
|
|
get { return (_sharedState != null); } |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Internal accessor to user size field.
|
|
|
|
/// Internal helper to access up-to-date UserSize property value.
|
|
|
|
/// </summary>
|
|
|
|
internal GridLength UserSize |
|
|
|
{ |
|
|
|
get { return (_sharedState != null ? _sharedState.UserSize : UserSizeValueCache); } |
|
|
|
} |
|
|
|
internal abstract GridLength UserSize { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Internal accessor to user min size field.
|
|
|
|
/// </summary>
|
|
|
|
internal double UserMinSize |
|
|
|
{ |
|
|
|
get { return (UserMinSizeValueCache); } |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Internal accessor to user max size field.
|
|
|
|
/// Internal helper to access up-to-date UserMinSize property value.
|
|
|
|
/// </summary>
|
|
|
|
internal double UserMaxSize |
|
|
|
{ |
|
|
|
get { return (UserMaxSizeValueCache); } |
|
|
|
} |
|
|
|
internal abstract double UserMinSize { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// DefinitionBase's index in the parents collection.
|
|
|
|
/// Internal helper to access up-to-date UserMaxSize property value.
|
|
|
|
/// </summary>
|
|
|
|
internal int Index |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
return (_parentIndex); |
|
|
|
} |
|
|
|
set |
|
|
|
{ |
|
|
|
Debug.Assert(value >= -1 && _parentIndex != value); |
|
|
|
_parentIndex = value; |
|
|
|
} |
|
|
|
} |
|
|
|
internal abstract double UserMaxSize { get; } |
|
|
|
|
|
|
|
private double _minSize; // used during measure to accumulate size for "Auto" and "Star" DefinitionBase's
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Layout-time user size type.
|
|
|
|
/// </summary>
|
|
|
|
internal Grid.LayoutTimeSizeType SizeType |
|
|
|
{ |
|
|
|
get { return (_sizeType); } |
|
|
|
set { _sizeType = value; } |
|
|
|
} |
|
|
|
|
|
|
|
internal Grid.LayoutTimeSizeType SizeType {get; set;} |
|
|
|
/// <summary>
|
|
|
|
/// Returns or sets measure size for the definition.
|
|
|
|
/// </summary>
|
|
|
|
internal double MeasureSize |
|
|
|
{ |
|
|
|
get { return (_measureSize); } |
|
|
|
set { _measureSize = value; } |
|
|
|
} |
|
|
|
internal double MeasureSize { get; set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns definition's layout time type sensitive preferred size.
|
|
|
|
@ -131,10 +66,10 @@ namespace Avalonia.Controls |
|
|
|
get |
|
|
|
{ |
|
|
|
double preferredSize = MinSize; |
|
|
|
if (_sizeType != Grid.LayoutTimeSizeType.Auto |
|
|
|
&& preferredSize < _measureSize) |
|
|
|
if (SizeType != Grid.LayoutTimeSizeType.Auto |
|
|
|
&& preferredSize < MeasureSize) |
|
|
|
{ |
|
|
|
preferredSize = _measureSize; |
|
|
|
preferredSize = MeasureSize; |
|
|
|
} |
|
|
|
return (preferredSize); |
|
|
|
} |
|
|
|
@ -143,11 +78,7 @@ namespace Avalonia.Controls |
|
|
|
/// <summary>
|
|
|
|
/// Returns or sets size cache for the definition.
|
|
|
|
/// </summary>
|
|
|
|
internal double SizeCache |
|
|
|
{ |
|
|
|
get { return (_sizeCache); } |
|
|
|
set { _sizeCache = value; } |
|
|
|
} |
|
|
|
internal double SizeCache { get; set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns min size.
|
|
|
|
@ -157,12 +88,6 @@ namespace Avalonia.Controls |
|
|
|
get |
|
|
|
{ |
|
|
|
double minSize = _minSize; |
|
|
|
if (UseSharedMinimum |
|
|
|
&& _sharedState != null |
|
|
|
&& minSize < _sharedState.MinSize) |
|
|
|
{ |
|
|
|
minSize = _sharedState.MinSize; |
|
|
|
} |
|
|
|
return (minSize); |
|
|
|
} |
|
|
|
|
|
|
|
@ -194,12 +119,6 @@ namespace Avalonia.Controls |
|
|
|
get |
|
|
|
{ |
|
|
|
double minSize = _minSize; |
|
|
|
if (_sharedState != null |
|
|
|
&& (UseSharedMinimum || !LayoutWasUpdated) |
|
|
|
&& minSize < _sharedState.MinSize) |
|
|
|
{ |
|
|
|
minSize = _sharedState.MinSize; |
|
|
|
} |
|
|
|
return (minSize); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -207,409 +126,11 @@ namespace Avalonia.Controls |
|
|
|
/// <summary>
|
|
|
|
/// Offset.
|
|
|
|
/// </summary>
|
|
|
|
internal double FinalOffset |
|
|
|
{ |
|
|
|
get { return _offset; } |
|
|
|
set { _offset = value; } |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Internal helper to access up-to-date UserSize property value.
|
|
|
|
/// </summary>
|
|
|
|
internal abstract GridLength UserSizeValueCache { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Internal helper to access up-to-date UserMinSize property value.
|
|
|
|
/// </summary>
|
|
|
|
internal abstract double UserMinSizeValueCache { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Internal helper to access up-to-date UserMaxSize property value.
|
|
|
|
/// </summary>
|
|
|
|
internal abstract double UserMaxSizeValueCache { get; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Protected. Returns <c>true</c> if this DefinitionBase instance is in parent's logical tree.
|
|
|
|
/// </summary>
|
|
|
|
internal bool InParentLogicalTree |
|
|
|
{ |
|
|
|
get { return (_parentIndex != -1); } |
|
|
|
} |
|
|
|
|
|
|
|
private static void OnSharedSizeGroupPropertyChanged(DefinitionBase definition, AvaloniaPropertyChangedEventArgs e) |
|
|
|
{ |
|
|
|
if (definition.InParentLogicalTree) |
|
|
|
{ |
|
|
|
string sharedSizeGroupId = (string)e.NewValue; |
|
|
|
|
|
|
|
if (definition._sharedState != null) |
|
|
|
{ |
|
|
|
// if definition is already registered AND shared size group id is changing,
|
|
|
|
// then un-register the definition from the current shared size state object.
|
|
|
|
definition._sharedState.RemoveMember(definition); |
|
|
|
definition._sharedState = null; |
|
|
|
} |
|
|
|
|
|
|
|
if ((definition._sharedState == null) && (sharedSizeGroupId != null)) |
|
|
|
{ |
|
|
|
// SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope;
|
|
|
|
// if (privateSharedSizeScope != null)
|
|
|
|
// {
|
|
|
|
// // if definition is not registered and both: shared size group id AND private shared scope
|
|
|
|
// // are available, then register definition.
|
|
|
|
// definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
|
|
|
|
// definition._sharedState.AddMember(definition);
|
|
|
|
// }
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <remarks>
|
|
|
|
/// Verifies that Shared Size Group Property string
|
|
|
|
/// a) not empty.
|
|
|
|
/// b) contains only letters, digits and underscore ('_').
|
|
|
|
/// c) does not start with a digit.
|
|
|
|
/// </remarks>
|
|
|
|
private static string SharedSizeGroupPropertyValueValid(DefinitionBase _, string value) |
|
|
|
{ |
|
|
|
// null is default value
|
|
|
|
if (value == null) |
|
|
|
{ |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
string id = (string)value; |
|
|
|
|
|
|
|
if (id != string.Empty) |
|
|
|
{ |
|
|
|
int i = -1; |
|
|
|
while (++i < id.Length) |
|
|
|
{ |
|
|
|
bool isDigit = Char.IsDigit(id[i]); |
|
|
|
|
|
|
|
if ((i == 0 && isDigit) |
|
|
|
|| !(isDigit |
|
|
|
|| Char.IsLetter(id[i]) |
|
|
|
|| '_' == id[i])) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (i == id.Length) |
|
|
|
{ |
|
|
|
return value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <see cref="PropertyMetadata.PropertyChangedCallback"/>
|
|
|
|
/// </summary>
|
|
|
|
/// <remark>
|
|
|
|
/// OnPrivateSharedSizeScopePropertyChanged is called when new scope enters or
|
|
|
|
/// existing scope just left. In both cases if the DefinitionBase object is already registered
|
|
|
|
/// in SharedSizeState, it should un-register and register itself in a new one.
|
|
|
|
/// </remark>
|
|
|
|
private static void OnPrivateSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) |
|
|
|
{ |
|
|
|
DefinitionBase definition = (DefinitionBase)d; |
|
|
|
|
|
|
|
if (definition.InParentLogicalTree) |
|
|
|
{ |
|
|
|
SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue; |
|
|
|
|
|
|
|
if (definition._sharedState != null) |
|
|
|
{ |
|
|
|
// if definition is already registered And shared size scope is changing,
|
|
|
|
// then un-register the definition from the current shared size state object.
|
|
|
|
definition._sharedState.RemoveMember(definition); |
|
|
|
definition._sharedState = null; |
|
|
|
} |
|
|
|
|
|
|
|
if ((definition._sharedState == null) && (privateSharedSizeScope != null)) |
|
|
|
{ |
|
|
|
string sharedSizeGroup = definition.SharedSizeGroup; |
|
|
|
if (sharedSizeGroup != null) |
|
|
|
{ |
|
|
|
// if definition is not registered and both: shared size group id AND private shared scope
|
|
|
|
// are available, then register definition.
|
|
|
|
definition._sharedState = privateSharedSizeScope.EnsureSharedState(definition.SharedSizeGroup); |
|
|
|
definition._sharedState.AddMember(definition); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Convenience accessor to UseSharedMinimum flag
|
|
|
|
/// </summary>
|
|
|
|
private bool UseSharedMinimum |
|
|
|
{ |
|
|
|
get { return _useSharedMinimum; } |
|
|
|
set { _useSharedMinimum = value; } |
|
|
|
} |
|
|
|
internal double FinalOffset { get; set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Convenience accessor to LayoutWasUpdated flag
|
|
|
|
/// </summary>
|
|
|
|
private bool LayoutWasUpdated |
|
|
|
{ |
|
|
|
get { return _layoutWasUpdated; } |
|
|
|
set { _layoutWasUpdated = value; } |
|
|
|
} |
|
|
|
|
|
|
|
private int _parentIndex = -1; // this instance's index in parent's children collection
|
|
|
|
|
|
|
|
private Grid.LayoutTimeSizeType _sizeType; // layout-time user size type. it may differ from _userSizeValueCache.UnitType when calculating "to-content"
|
|
|
|
|
|
|
|
private double _minSize; // used during measure to accumulate size for "Auto" and "Star" DefinitionBase's
|
|
|
|
private double _measureSize; // size, calculated to be the input contstraint size for Child.Measure
|
|
|
|
private double _sizeCache; // cache used for various purposes (sorting, caching, etc) during calculations
|
|
|
|
private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case)
|
|
|
|
|
|
|
|
private SharedSizeState _sharedState; // reference to shared state object this instance is registered with
|
|
|
|
private bool _layoutWasUpdated; |
|
|
|
private bool _useSharedMinimum; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Collection of shared states objects for a single scope
|
|
|
|
/// </summary>
|
|
|
|
private class SharedSizeScope |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Returns SharedSizeState object for a given group.
|
|
|
|
/// Creates a new StatedState object if necessary.
|
|
|
|
/// </summary>
|
|
|
|
internal SharedSizeState EnsureSharedState(string sharedSizeGroup) |
|
|
|
{ |
|
|
|
// check that sharedSizeGroup is not default
|
|
|
|
Debug.Assert(sharedSizeGroup != null); |
|
|
|
|
|
|
|
SharedSizeState sharedState = _registry[sharedSizeGroup] as SharedSizeState; |
|
|
|
if (sharedState == null) |
|
|
|
{ |
|
|
|
sharedState = new SharedSizeState(this, sharedSizeGroup); |
|
|
|
_registry[sharedSizeGroup] = sharedState; |
|
|
|
} |
|
|
|
return (sharedState); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Removes an entry in the registry by the given key.
|
|
|
|
/// </summary>
|
|
|
|
internal void Remove(object key) |
|
|
|
{ |
|
|
|
Debug.Assert(_registry.Contains(key)); |
|
|
|
_registry.Remove(key); |
|
|
|
} |
|
|
|
|
|
|
|
private Hashtable _registry = new Hashtable(); // storage for shared state objects
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Implementation of per shared group state object
|
|
|
|
/// Returns <c>true</c> if this definition is a part of shared group.
|
|
|
|
/// </summary>
|
|
|
|
private class SharedSizeState |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Default ctor.
|
|
|
|
/// </summary>
|
|
|
|
internal SharedSizeState(SharedSizeScope sharedSizeScope, string sharedSizeGroupId) |
|
|
|
{ |
|
|
|
Debug.Assert(sharedSizeScope != null && sharedSizeGroupId != null); |
|
|
|
_sharedSizeScope = sharedSizeScope; |
|
|
|
_sharedSizeGroupId = sharedSizeGroupId; |
|
|
|
_registry = new List<DefinitionBase>(); |
|
|
|
// _layoutUpdated = new EventHandler(OnLayoutUpdated);
|
|
|
|
_broadcastInvalidation = true; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Adds / registers a definition instance.
|
|
|
|
/// </summary>
|
|
|
|
internal void AddMember(DefinitionBase member) |
|
|
|
{ |
|
|
|
Debug.Assert(!_registry.Contains(member)); |
|
|
|
_registry.Add(member); |
|
|
|
Invalidate(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Removes / un-registers a definition instance.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// If the collection of registered definitions becomes empty
|
|
|
|
/// instantiates self removal from owner's collection.
|
|
|
|
/// </remarks>
|
|
|
|
internal void RemoveMember(DefinitionBase member) |
|
|
|
{ |
|
|
|
Invalidate(); |
|
|
|
_registry.Remove(member); |
|
|
|
|
|
|
|
if (_registry.Count == 0) |
|
|
|
{ |
|
|
|
_sharedSizeScope.Remove(_sharedSizeGroupId); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Propogates invalidations for all registered definitions.
|
|
|
|
/// Resets its own state.
|
|
|
|
/// </summary>
|
|
|
|
internal void Invalidate() |
|
|
|
{ |
|
|
|
_userSizeValid = false; |
|
|
|
|
|
|
|
if (_broadcastInvalidation) |
|
|
|
{ |
|
|
|
for (int i = 0, count = _registry.Count; i < count; ++i) |
|
|
|
{ |
|
|
|
Grid parentGrid = (Grid)(_registry[i].Parent); |
|
|
|
parentGrid.Invalidate(); |
|
|
|
} |
|
|
|
_broadcastInvalidation = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Makes sure that one and only one layout updated handler is registered for this shared state.
|
|
|
|
/// </summary>
|
|
|
|
internal void EnsureDeferredValidation(IControl layoutUpdatedHost) |
|
|
|
{ |
|
|
|
if (_layoutUpdatedHost == null) |
|
|
|
{ |
|
|
|
_layoutUpdatedHost = layoutUpdatedHost; |
|
|
|
// PORTING HACK... Remove this when resolved.
|
|
|
|
_layoutUpdatedHost.GetSubject(Visual.BoundsProperty).Subscribe(p => _layoutUpdated?.Invoke(this, null)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// DefinitionBase's specific code.
|
|
|
|
/// </summary>
|
|
|
|
internal double MinSize |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
if (!_userSizeValid) { EnsureUserSizeValid(); } |
|
|
|
return (_minSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// DefinitionBase's specific code.
|
|
|
|
/// </summary>
|
|
|
|
internal GridLength UserSize |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
if (!_userSizeValid) { EnsureUserSizeValid(); } |
|
|
|
return (_userSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void EnsureUserSizeValid() |
|
|
|
{ |
|
|
|
_userSize = new GridLength(1, GridUnitType.Auto); |
|
|
|
|
|
|
|
for (int i = 0, count = _registry.Count; i < count; ++i) |
|
|
|
{ |
|
|
|
Debug.Assert(_userSize.GridUnitType == GridUnitType.Auto |
|
|
|
|| _userSize.GridUnitType == GridUnitType.Pixel); |
|
|
|
|
|
|
|
GridLength currentGridLength = _registry[i].UserSizeValueCache; |
|
|
|
if (currentGridLength.GridUnitType == GridUnitType.Pixel) |
|
|
|
{ |
|
|
|
if (_userSize.GridUnitType == GridUnitType.Auto) |
|
|
|
{ |
|
|
|
_userSize = currentGridLength; |
|
|
|
} |
|
|
|
else if (_userSize.Value < currentGridLength.Value) |
|
|
|
{ |
|
|
|
_userSize = currentGridLength; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// taking maximum with user size effectively prevents squishy-ness.
|
|
|
|
// this is a "solution" to avoid shared definitions from been sized to
|
|
|
|
// different final size at arrange time, if / when different grids receive
|
|
|
|
// different final sizes.
|
|
|
|
_minSize = _userSize.IsAbsolute ? _userSize.Value : 0.0; |
|
|
|
|
|
|
|
_userSizeValid = true; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// OnLayoutUpdated handler. Validates that all participating definitions
|
|
|
|
/// have updated min size value. Forces another layout update cycle if needed.
|
|
|
|
/// </summary>
|
|
|
|
private void OnLayoutUpdated(object sender, EventArgs e) |
|
|
|
{ |
|
|
|
double sharedMinSize = 0; |
|
|
|
|
|
|
|
// accumulate min size of all participating definitions
|
|
|
|
for (int i = 0, count = _registry.Count; i < count; ++i) |
|
|
|
{ |
|
|
|
sharedMinSize = Math.Max(sharedMinSize, _registry[i].MinSize); |
|
|
|
} |
|
|
|
|
|
|
|
bool sharedMinSizeChanged = !MathUtilities.AreClose(_minSize, sharedMinSize); |
|
|
|
|
|
|
|
// compare accumulated min size with min sizes of the individual definitions
|
|
|
|
for (int i = 0, count = _registry.Count; i < count; ++i) |
|
|
|
{ |
|
|
|
DefinitionBase definitionBase = _registry[i]; |
|
|
|
|
|
|
|
if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) |
|
|
|
{ |
|
|
|
// if definition's min size is different, then need to re-measure
|
|
|
|
if (!MathUtilities.AreClose(sharedMinSize, definitionBase.MinSize)) |
|
|
|
{ |
|
|
|
Grid parentGrid = (Grid)definitionBase.Parent; |
|
|
|
parentGrid.InvalidateMeasure(); |
|
|
|
definitionBase.UseSharedMinimum = true; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
definitionBase.UseSharedMinimum = false; |
|
|
|
|
|
|
|
// if measure is valid then also need to check arrange.
|
|
|
|
// Note: definitionBase.SizeCache is volatile but at this point
|
|
|
|
// it contains up-to-date final size
|
|
|
|
if (!MathUtilities.AreClose(sharedMinSize, definitionBase.SizeCache)) |
|
|
|
{ |
|
|
|
Grid parentGrid = (Grid)definitionBase.Parent; |
|
|
|
parentGrid.InvalidateArrange(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
definitionBase.LayoutWasUpdated = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
_minSize = sharedMinSize; |
|
|
|
|
|
|
|
// _layoutUpdatedHost.LayoutUpdated -= _layoutUpdated;
|
|
|
|
_layoutUpdatedHost = null; |
|
|
|
|
|
|
|
_broadcastInvalidation = true; |
|
|
|
} |
|
|
|
|
|
|
|
private readonly SharedSizeScope _sharedSizeScope; // the scope this state belongs to
|
|
|
|
private readonly string _sharedSizeGroupId; // Id of the shared size group this object is servicing
|
|
|
|
private readonly List<DefinitionBase> _registry; // registry of participating definitions
|
|
|
|
private readonly EventHandler _layoutUpdated; // instance event handler for layout updated event
|
|
|
|
private IControl _layoutUpdatedHost; // IControl for which layout updated event handler is registered
|
|
|
|
private bool _broadcastInvalidation; // "true" when broadcasting of invalidation is needed
|
|
|
|
private bool _userSizeValid; // "true" when _userSize is up to date
|
|
|
|
private GridLength _userSize; // shared state
|
|
|
|
private double _minSize; // shared state
|
|
|
|
} |
|
|
|
internal bool IsShared { get; set; } |
|
|
|
} |
|
|
|
} |