/// <summary> /// Measures all of the RibbonGroups, and asks them to resize themselves appropriately /// to fit within the available room in the GroupsContainer. /// </summary> /// <param name="availableSize">The available size that this element can give to child elements.</param> /// <returns> /// The size that the groups container determines it needs during layout, based /// on its calculations of child element sizes. /// </returns> protected override Size MeasureOverride(Size availableSize) { RibbonTab ribbonTab = ParentRibbonTab; double remainingSpace = 0; Size desiredSize = BasicMeasure(availableSize, out remainingSpace); UIElementCollection children = InternalChildren; if (children.Count != _cachedChildCount) { ResetNextIncreaseGroupCache(); _cachedChildCount = children.Count; } if (DoubleUtil.GreaterThan(remainingSpace, 0)) { // nudging the positive remaining space by a pixel // protects against aggregation of double errors and // provides a better appreance. remainingSpace = Math.Max(0, remainingSpace - 1); } if ((DoubleUtil.GreaterThanOrClose(_cachedRemainingSpace, 0) && (DoubleUtil.LessThan(remainingSpace, 0) || DoubleUtil.GreaterThan(remainingSpace, _cachedRemainingSpace))) || (DoubleUtil.LessThan(_cachedRemainingSpace, 0) && DoubleUtil.GreaterThan(remainingSpace, 0))) { if (ribbonTab != null) { double?lastPreIncreaseRemainingSpace = null; while (DoubleUtil.GreaterThan(remainingSpace, 0)) { // When there is remaining space try to give it // to stars, which qualify to increase before // next group resize. desiredSize = StarMeasure(availableSize, desiredSize, ribbonTab, ref remainingSpace); // When there is more remaining space, increase // the size of the next group. if (DoubleUtil.GreaterThan(remainingSpace, 0)) { if (double.IsNaN(_nextGroupIncreaseWidth) || DoubleUtil.GreaterThanOrClose(remainingSpace, _nextGroupIncreaseWidth)) { if (ribbonTab.IncreaseNextGroupSize()) { ResetNextIncreaseGroupCache(); lastPreIncreaseRemainingSpace = remainingSpace; desiredSize = BasicMeasure(availableSize, out remainingSpace); } else { break; } } else { break; } } } double preDecreaseGroupRemainingSpace = remainingSpace; while (DoubleUtil.LessThan(remainingSpace, 0)) { // When the remaining space is negative decrease the // next groups size. if (ribbonTab.DecreaseNextGroupSize()) { desiredSize = BasicMeasure(availableSize, out remainingSpace); if (lastPreIncreaseRemainingSpace != null) { // Though in most of the cases we expect that the desired size of the // entire subtree is up to date synchronously, there are some cases where desired // size of subtree gets updated asynchronously(eg. where bindings // impacting desired size resolve at a later time). To gaurd against infinite // loops in such cases, if this decrease operation is to compensate any unnecessary // increase operation performed above, then use the remaining space // computed before such corresponding unnecessary increase operation, instead // of the value computed post decrease which may be inaccurate due to some // pending async updates. On the other hand if the group remains in // same stage and when such async update happens at a later point of time, // this measure would be executed again and hence fixing things. remainingSpace = lastPreIncreaseRemainingSpace.Value; // The remaining space needed to successfully perform the // preceeding group increase without needing to do a compensating // group decrease is cached to be used to optimize out the // unsuccessful group size increases on further increase // in remaining space. _nextGroupIncreaseWidth = lastPreIncreaseRemainingSpace.Value - preDecreaseGroupRemainingSpace; lastPreIncreaseRemainingSpace = null; } else { ResetNextIncreaseGroupCache(); } if (DoubleUtil.GreaterThan(remainingSpace, 0)) { // Now if there is remaining space, give it to the // qualified stars. desiredSize = StarMeasure(availableSize, desiredSize, ribbonTab, ref remainingSpace); } } else { break; } } } } else if (DoubleUtil.GreaterThan(remainingSpace, 0)) { desiredSize = StarMeasure(availableSize, desiredSize, ribbonTab, ref remainingSpace); } _cachedRemainingSpace = remainingSpace; //// Scroll if not enough space return(desiredSize); }