В RichTextBox неправильно выделяются символы

Если просто запустить простой пример кода то первые нажатия на кнопку не принесут эффекта В TextRange.Text будет "". И даже если ставить проверку что бы оно пропускало данные случаи, то все равно не будет работать. Так как же мне выделить и поменять текст?

<Grid>
        <RichTextBox x:Name="TextField" HorizontalAlignment="Left" Height="180" Margin="258,43,0,0" VerticalAlignment="Top" Width="316">
            <FlowDocument>
                <Paragraph>
                    <Run Text="RichTextBox"/>
                </Paragraph>
            </FlowDocument>
        </RichTextBox>
        <Button Content="Click" HorizontalAlignment="Left" Height="44" Margin="258,268,0,0" VerticalAlignment="Top" Width="316" Click="Button_Click"/>
</Grid>
int i = 0;
        public MainWindow()
        {
            InitializeComponent();
            string text = "aaaaa";
            TextField.IsReadOnly = true;
            TextField.Document.Blocks.Clear();
            TextField.Document.Blocks.Add(new Paragraph(new Run(text)));
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TextRange rangeForLetter = new 
            TextRange(TextField.Document.ContentStart.GetPositionAtOffset(i), 
            TextField.Document.ContentStart.GetPositionAtOffset(i + 1));

            rangeForLetter.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
            i++;
        }

Ответы (1 шт):

Автор решения: VladD

Например, можно сделать так:

XAML

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" Height="200" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <RichTextBox x:Name="TextField" IsReadOnly="True" Grid.Row="0">
            <FlowDocument>
                <Paragraph Margin="0">
                    <Run Text="hello world"/>
                </Paragraph>
                <Paragraph Margin="0">
                    <Run Text="goodbye world"/>
                </Paragraph>
            </FlowDocument>
        </RichTextBox>
        <Button Content="Next" HorizontalAlignment="Center" Click="PaintNext"
                Grid.Row="1" Margin="5" MinWidth="75" x:Name="NextButton"/>
    </Grid>
</Window>

Code-behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        curr = FindNextSymbol(TextField.Document.ContentStart);
        NextButton.IsEnabled = curr != null;
    }

    TextRange curr;

    TextRange FindNextSymbol(TextPointer from)
    {
        while (true)
        {
            var ctx = from.GetPointerContext(LogicalDirection.Forward);
            if (ctx == TextPointerContext.None)
                return null;
            var next = from.GetPositionAtOffset(1, LogicalDirection.Forward);
            if (ctx == TextPointerContext.Text)
                return new TextRange(from, next);
            from = next;
        }
    }

    void PaintNext(object sender, RoutedEventArgs e)
    {
        if (curr == null)
            return;
        curr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Red);
        curr = FindNextSymbol(curr.End);
        if (curr == null)
            NextButton.IsEnabled = false;
    }
}

Результат:

КДПВ

Объяснение: Позиции в RichTextBox не обязательно соответствуют границам букв. Всякие невидимые элементы наподобие начала/конца абзацев тоже являются позицией. Для того, чтобы найти позицию текста, мы идём по одному шагу от начала документа вправо, и проверяем тип содержимого справа от текущей позиции. Как только находим текстовый тип, окрашиваем его в нужный цвет.


Обратите внимание на две вещи. Во-первых, код, который я привёл, не следует принципам MVVM (потому, что он занимается чисто визуальной логикой). Затем, я перерисовал ваш UI с использованием layout manager'а, так должно работать с разными размерами окна.

→ Ссылка