/// <summary> /// To fix infinity measure loop we must override MeasureOverride /// </summary> protected override Size MeasureOverride(Size availableSize) { var desiredSize = new Size(); // Don't measure the child if tabs are not ready yet or Ribbon is collapsed. if (Ribbon == null || Ribbon.IsCollapsed) { return(desiredSize); } var remainingSpace = availableSize.Width; var invalidateThPanel = false; RibbonTabHeadersPanel tabHeadersPanel = null; if (Ribbon.InternalPropertyGet("RibbonTabHeaderItemsControl") is RibbonTabHeaderItemsControl ribbonTabHeaderItemsControl) { tabHeadersPanel = ribbonTabHeaderItemsControl.InternalPropertyGet("InternalItemsHost") as RibbonTabHeadersPanel; } var tabHeadersPanelSpaceAvailable = (double?)tabHeadersPanel?.InternalPropertyGet("SpaceAvailable") ?? 0.0; foreach (RibbonContextualTabGroup tabGroupHeader in InternalChildren) { double width = 0; tabGroupHeader.InternalPropertySet("ArrangeWidth", 0); tabGroupHeader.InternalPropertySet("ArrangeX", 0); tabGroupHeader.InternalPropertySet("IdealDesiredWidth", 0.0); if (tabGroupHeader.Visibility == Visibility.Visible && tabGroupHeader.InternalPropertyGet("FirstVisibleTab") != null && remainingSpace > double.Epsilon) { // Measure the maximum desired width // TabHeaders should be padded up more if needed. // Also we need to determine if we need to show the label tooltip tabGroupHeader.Measure(new Size(double.PositiveInfinity, availableSize.Height)); tabGroupHeader.InternalPropertySet("IdealDesiredWidth", tabGroupHeader.DesiredSize.Width); // If TabHeadersPanel has space to expand, then invalidate it so that TabHeaders add extra Padding to themselves. var idealDesiredWidth = (double)tabGroupHeader.InternalPropertyGet("IdealDesiredWidth"); var tabsDesiredWidth = (double)tabGroupHeader.InternalPropertyGet("TabsDesiredWidth"); var desiredExtraPadding = idealDesiredWidth - tabsDesiredWidth; var desiredExtraPaddingFromPreviousMeasure = GetDesiredExtraPadding(tabGroupHeader); // Bug fix for infinity measure loop when tabs group panel could not extend its size. if (Math.Abs(desiredExtraPaddingFromPreviousMeasure - desiredExtraPadding) > double.Epsilon && desiredExtraPadding > double.Epsilon && tabHeadersPanelSpaceAvailable > double.Epsilon) { //Remember desiredExtraPadding for current tabGroupHeader SetDesiredExtraPadding(tabGroupHeader, desiredExtraPadding); invalidateThPanel = true; } else { //Clear desiredExtraPadding for current tabGroupHeader SetDesiredExtraPadding(tabGroupHeader, 0); } width = tabsDesiredWidth; // If the difference between tabGroupHeader.TabsDesiredWidth and remainingSpace is less // than 1e-10 then assume that both are same. This is because TextBlock is very sensitive to // even a minute floating point difference and displays ellipsis even when sufficient // space is available. if (Math.Abs(tabsDesiredWidth - remainingSpace) > double.Epsilon) { // Clip on the left side width = Math.Min(tabsDesiredWidth, remainingSpace); } tabGroupHeader.InternalPropertySet("ArrangeWidth", width); tabGroupHeader.Measure(new Size(width, availableSize.Height)); // If label is truncated - show the tooltip idealDesiredWidth = (double)tabGroupHeader.InternalPropertyGet("IdealDesiredWidth"); tabGroupHeader.InternalPropertySet("ShowLabelToolTip", idealDesiredWidth > width); remainingSpace = remainingSpace - width; } desiredSize.Width += width; desiredSize.Height = Math.Max(desiredSize.Height, tabGroupHeader.DesiredSize.Height); } var waitingForMeasure = (bool)this.InternalPropertyGet("WaitingForMeasure"); if (waitingForMeasure || invalidateThPanel) { tabHeadersPanel?.InvalidateMeasure(); } return(desiredSize); }
protected override Size MeasureOverride(Size availableSize) { Size desiredSize = new Size(); // Don't measure the child if tabs are not ready yet or Ribbon is collapsed. if (Ribbon != null && !Ribbon.IsCollapsed) { double remainingSpace = availableSize.Width; bool invalidateTHPanel = false; RibbonTabHeadersPanel tabHeadersPanel = null; if (Ribbon.RibbonTabHeaderItemsControl != null) { tabHeadersPanel = Ribbon.RibbonTabHeaderItemsControl.InternalItemsHost as RibbonTabHeadersPanel; } double tabHeadersPanelSpaceAvailable = (tabHeadersPanel != null) ? tabHeadersPanel.SpaceAvailable : 0.0; foreach (RibbonContextualTabGroup tabGroupHeader in InternalChildren) { double width = 0; tabGroupHeader.ArrangeWidth = 0; tabGroupHeader.ArrangeX = 0; tabGroupHeader.IdealDesiredWidth = 0.0; if (tabGroupHeader.Visibility == Visibility.Visible && tabGroupHeader.FirstVisibleTab != null && DoubleUtil.GreaterThanOrClose(remainingSpace, 0.0)) { // Measure the maximum desired width // TabHeaders should be padded up more if needed. // Also we need to determine if we need to show the label tooltip tabGroupHeader.Measure(new Size(double.PositiveInfinity, availableSize.Height)); tabGroupHeader.IdealDesiredWidth = tabGroupHeader.DesiredSize.Width; // If TabHeadersPanel has space to expand, then invalidate it so that TabHeaders add extra Padding to themselves. double desiredExtraPadding = tabGroupHeader.IdealDesiredWidth - tabGroupHeader.TabsDesiredWidth; if (DoubleUtil.GreaterThan(desiredExtraPadding, 0.0) && DoubleUtil.GreaterThan(tabHeadersPanelSpaceAvailable, 0.0)) { invalidateTHPanel = true; } width = tabGroupHeader.TabsDesiredWidth; // If the difference between tabGroupHeader.TabsDesiredWidth and remainingSpace is less // than 1e-10 then assume that both are same. This is because TextBlock is very sensitive to // even a minute floating point difference and displays ellipsis even when sufficient // space is available. if (Math.Abs(tabGroupHeader.TabsDesiredWidth - remainingSpace) > _desiredWidthEpsilon) { // Clip on the left side width = Math.Min(tabGroupHeader.TabsDesiredWidth, remainingSpace); } tabGroupHeader.ArrangeWidth = width; tabGroupHeader.Measure(new Size(width, availableSize.Height)); // If label is truncated - show the tooltip tabGroupHeader.ShowLabelToolTip = DoubleUtil.GreaterThan(tabGroupHeader.IdealDesiredWidth, width); remainingSpace = remainingSpace - width; } desiredSize.Width += width; desiredSize.Height = Math.Max(desiredSize.Height, tabGroupHeader.DesiredSize.Height); } if (WaitingForMeasure || invalidateTHPanel) { if (tabHeadersPanel != null) { tabHeadersPanel.InvalidateMeasure(); } } } return(desiredSize); }