Skip to content

Instantly share code, notes, and snippets.

@cnbluefire
Created March 16, 2026 13:57
Show Gist options
  • Select an option

  • Save cnbluefire/d444e62b8f8723a7a7d573c2530dcf96 to your computer and use it in GitHub Desktop.

Select an option

Save cnbluefire/d444e62b8f8723a7a7d573c2530dcf96 to your computer and use it in GitHub Desktop.
WinUI3 get TextBlock character bounding box.
public static class TextBlockExtensions
{
// https://github.com/microsoft/microsoft-ui-xaml/blob/main/src/dxaml/xcp/core/text/TextBlock/TextBlockView.cpp#L606
public static TextPointer GetAdjustedPosition(this TextBlock textBlock, int charIndex)
{
const int PlaceHolderPositionsForInlines = 2;
var contentLength = textBlock.Text.Length + 2 * PlaceHolderPositionsForInlines;
int charCount = charIndex;
int adjustedPosition = 0;
// Correct out of bound indexes to valid ones
if (charIndex < 0)
{
adjustedPosition = PlaceHolderPositionsForInlines;
}
else if (charIndex >= (contentLength - (int)PlaceHolderPositionsForInlines))
{
adjustedPosition = contentLength - (int)PlaceHolderPositionsForInlines;
}
else
{
adjustedPosition = charIndex + PlaceHolderPositionsForInlines;
System.Diagnostics.Debug.Assert(adjustedPosition <= (int)contentLength - (int)PlaceHolderPositionsForInlines);
}
return textBlock.ContentStart.GetPositionAtOffset(adjustedPosition, LogicalDirection.Forward);
}
public static TextBlockCharacterBoundingBox GetElementBoundingBox(this TextBlock textBlock, int charIndex)
{
var text = textBlock.Text;
ArgumentOutOfRangeException.ThrowIfLessThan(charIndex, 0);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(charIndex, text.Length);
var pointer = GetAdjustedPosition(textBlock, charIndex);
var nextPointer = pointer.GetPositionAtOffset(1, LogicalDirection.Forward);
var rect1 = pointer.GetCharacterRect(LogicalDirection.Forward);
var rect2 = nextPointer.GetCharacterRect(LogicalDirection.Backward);
var ch = text[charIndex];
var p1x = Math.Min(rect1.X, rect2.X);
var p1y = Math.Min(rect1.Y, rect2.Y);
var p2x = Math.Max(rect1.X, rect2.X);
var p2y = Math.Max(rect1.Y + rect1.Height, rect2.Y + rect2.Height);
var rect = new Rect(new Point(p1x, p1y), new Point(p2x, p2y));
return new TextBlockCharacterBoundingBox(charIndex, ch, rect);
}
public record struct TextBlockCharacterBoundingBox(int CharacterIndex, char Character, Rect BoundingBox);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment