Ну, я могу предложить несколько хакерский способ сделать это.
Во-первых, обратите внимание, что вы можете поместить элементы пользовательского интерфейса в FlowDocument
. Так что возможно что-то вроде этого:
<RichTextBox>
<FlowDocument>
<Paragraph>
<InlineUIContainer>
<TextBlock>This is your label: </TextBlock>
</InlineUIContainer>
<Run>And this is the editable text.</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
Теперь проблема заключается в том, что пользователь не может редактировать InlineUIContainer
. Это действительно две проблемы.
Первая проблема заключается в том, что пользователь не может выбрать it. Для этого вам нужно обработать событие SelectionChanged
. В этом случае найдите первый InlineUIContainer
в документе RTB, а если Selection.Start
до этого, измените его.
private void RichTextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
RichTextBox rtb = (RichTextBox) sender;
if (rtb == null) return;
InlineUIContainer c = rtb.Document
.Blocks
.Where(x => x is Paragraph)
.Cast<Paragraph>()
.SelectMany(x => x.Inlines)
.Where(x => x is InlineUIContainer)
.Cast<InlineUIContainer>()
.FirstOrDefault();
if (c == null) return;
if (rtb.Selection.Start.CompareTo(c.ElementEnd) < 0)
{
rtb.Selection.Select(c.ElementEnd, rtb.Selection.End);
}
}
Вероятно, есть более простой способ сформулировать этот запрос LINQ, но мне это нравится. И это не на 100% идеально; если вы выделите текст и перетащите его влево на TextBlock
, выделение будет потеряно. Я уверен, что это можно исправить. Но это работает довольно хорошо. Он даже обрабатывает случай, когда пользователь перемещается с помощью клавиш со стрелками.
Только это и доставит вас почти до самого конца. Другая вещь, которая может вас испортить, это то, что пользователь помещает курсор в самое начало текста и нажимает BACKSPACE.
Обработка, которая требует чего-то похожего: сравните позицию каретки с концом первой InlineUIElement
и отмените BACKSPACE (пометив событие как обработанное), если каретка находится в этой позиции:
private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Back)
{
return;
}
RichTextBox rtb = (RichTextBox)sender;
if (rtb == null) return;
InlineUIContainer c = rtb.Document
.Blocks
.Where(x => x is Paragraph)
.Cast<Paragraph>()
.SelectMany(x => x.Inlines)
.Where(x => x is InlineUIContainer)
.Cast<InlineUIContainer>()
.FirstOrDefault();
if (c == null) return;
if (rtb.CaretPosition.CompareTo(c.ElementEnd.GetInsertionPosition(LogicalDirection.Forward)) <= 0)
{
e.Handled = true;
}
}