private static void TrimText(TextBlock textBlock, string text, double size, ICollection <string> segments, double epsilon, bool reversed) { while (true) { if (text.Length == 1) { var textSize = TextBlockTrimmer.MeasureString(textBlock, text); if (textSize <= size) { segments.Add(text); } return; } var halfLength = Math.Max(1, text.Length / 2); var firstHalf = reversed ? text.Substring(halfLength) : text.Substring(0, halfLength); var remainingSize = size - TextBlockTrimmer.MeasureString(textBlock, firstHalf); if (remainingSize < 0) { // only one character and it's still too large for the room, skip it if (firstHalf.Length == 1) { return; } text = firstHalf; continue; } segments.Add(firstHalf); if (remainingSize > epsilon) { var secondHalf = reversed ? text.Substring(0, halfLength) : text.Substring(halfLength); text = secondHalf; size = remainingSize; continue; } break; } }
private void TrimText() { var textBlock = (TextBlock)this.Content; if (textBlock == null) { return; } if (DesignerProperties.GetIsInDesignMode(textBlock)) { return; } var freeSize = _constraint.Width - this.Padding.Left - this.Padding.Right - textBlock.Margin.Left - textBlock.Margin.Right; // ReSharper disable once CompareOfFloatsByEqualityOperator if (freeSize <= 0) { return; } using (this.BlockTextChangedEvent()) { // this actually sets textBlock's text back to its original value var desiredSize = TextBlockTrimmer.MeasureString(textBlock, _originalText); if (desiredSize <= freeSize) { return; } var ellipsisSize = TextBlockTrimmer.MeasureString(textBlock, ELLIPSIS); freeSize -= ellipsisSize; var epsilon = ellipsisSize / 3; if (freeSize < epsilon) { textBlock.Text = _originalText; return; } var segments = new List <string>(); var builder = new StringBuilder(); switch (this.EllipsisPosition) { case EllipsisPosition.End: TextBlockTrimmer.TrimText(textBlock, _originalText, freeSize, segments, epsilon, false); foreach (var segment in segments) { builder.Append(segment); } builder.Append(ELLIPSIS); break; case EllipsisPosition.Start: TextBlockTrimmer.TrimText(textBlock, _originalText, freeSize, segments, epsilon, true); builder.Append(ELLIPSIS); foreach (var segment in ((IEnumerable <string>)segments).Reverse()) { builder.Append(segment); } break; case EllipsisPosition.Middle: var textLength = _originalText.Length / 2; var firstHalf = _originalText.Substring(0, textLength); var secondHalf = _originalText.Substring(textLength); freeSize /= 2; TextBlockTrimmer.TrimText(textBlock, firstHalf, freeSize, segments, epsilon, false); foreach (var segment in segments) { builder.Append(segment); } builder.Append(ELLIPSIS); segments.Clear(); TextBlockTrimmer.TrimText(textBlock, secondHalf, freeSize, segments, epsilon, true); foreach (var segment in ((IEnumerable <string>)segments).Reverse()) { builder.Append(segment); } break; default: throw new NotSupportedException(); } textBlock.Text = builder.ToString(); } }