Для меня код, который вы разместили, выглядит подверженным ошибкам. Это будет работать, только если TextBlock
содержит простой текст. Но когда вы используете Inline
элементы, такие как Run
, Bold
или Underline
, у вас больше не будет простого текста в качестве содержимого, но также есть контекстные маркеры, такие как теги для встроенных элементов. Я предполагаю, что это где ваше смещение на основе string.Substring
терпит неудачу.
Решение состоит в том, чтобы создать TextRange
из полученных TextPointer
результатов и извлечь простой текст с помощью свойства TextRange.Text
.
Следующая реализация поддерживает оба: простой текст, заданный с помощью свойство TextBlock.Text
и текст, заданный с использованием элементов Inline
:
public static IEnumerable<string> GetLines(this TextBlock source)
{
TextPointer lineStart = source.ContentStart.GetPositionAtOffset(1, LogicalDirection.Forward);
do
{
TextPointer lineEnd = lineStart.GetLineStartPosition(1) ?? source.ContentEnd;
var textRange = new TextRange(lineStart, lineEnd);
lineStart = lineEnd;
yield return textRange.Text;
}
while (lineStart.IsAtLineStartPosition);
}
Примечания
Важно дождаться возникновения события TextBlock.Loaded
. Это связано с тем, что TextBlock
разбивает одну текстовую строку на строки во время процесса UIElement.Measure
, так как в этот момент элемент управления знает желаемый размер и, следовательно, максимально доступную ширину строки. UIElement.Measure
вызывается механизмом рендеринга после начала загрузки макета.
Пример
MainWindow.xaml
<Window>
<TextBlock x:Name="TextBlock"
TextWrapping="Wrap"
Width="100">
<TextBlock.Inlines>
<Run
Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat," />
<Bold>
<Bold.Inlines>
<Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, conse" />
</Bold.Inlines>
</Bold>
<LineBreak />
<LineBreak />
<LineBreak />
<Underline>
<Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut " />
<Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut " />
</Underline>
<Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut " />
</TextBlock.Inlines>
</TextBlock>
</Window>
MainWindow.xaml.cs
partial class MainWindow : Window
{
public MainWindow()
{
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, EventArgs e)
{
var lines = this.TextBlock.GetLines().ToList(); // Returns 54 lines
}
}