嗯,我可以建議一個有點ha way的方法來做到這一點。
首先,請注意,你可以把UI元素成FlowDocument
。這樣就使得這樣的可能:
<RichTextBox>
<FlowDocument>
<Paragraph>
<InlineUIContainer>
<TextBlock>This is your label: </TextBlock>
</InlineUIContainer>
<Run>And this is the editable text.</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
現在的問題變成,從編輯InlineUIContainer
保持用戶。這實際上是兩個問題。
第一個問題是從保持用戶選擇它。要做到這一點,你必須處理SelectionChanged
事件。如果發現RTB文檔中的第一個InlineUIContainer
,並且如果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;
}
}