我想突出显示RichTextBlock中的选定文本,但是当我在选择文本后单击“ btnHighlight”按钮时,突出显示的文本与所选内容不匹配(也许是由于超链接,但是如何解决该问题) ?)。我在哪里错了?
MainPage.xaml:
<Grid>
<RichTextBlock Name="Rtb" Margin="0,150,0,150" Width="300">
<Paragraph TextIndent="0">
<Hyperlink UnderlineStyle="None" CharacterSpacing="0">
<Run Text="1" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text a" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="2" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text b" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="3" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text c" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="4" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text d" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="5" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text e" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="6" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text f" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="7" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text g" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="8" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text h" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="9" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text i" FontSize="20"/>
<Hyperlink UnderlineStyle="None">
<Run Text="10" FontSize="20" FontWeight="Bold"/>
</Hyperlink>
<Run Text="Text l" FontSize="20"/>
</Paragraph>
</RichTextBlock>
<Button x:Name="btnHighlight" Click="btnHighlight_Click" Content="Highlight" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<Button x:Name="btnRemoveHighlight" Click="btnRemoveHighlight_Click" Content="Remove" HorizontalAlignment="Left" Margin="110,10,0,0" VerticalAlignment="Top"/>
</Grid>
MainPage.xaml.cs:
private void btnHighlight_Click(object sender, RoutedEventArgs e)
{
int selectionStart = Rtb.SelectionStart.Offset;
int selectionEnd = Rtb.SelectionEnd.Offset;
int lenght = selectionEnd - selectionStart;
TextRange textRange = new TextRange() { StartIndex = selectionStart, Length = lenght };
TextHighlighter highlighter = new TextHighlighter();
highlighter.Background = new SolidColorBrush(Colors.Yellow);
highlighter.Ranges.Add(textRange);
Rtb.TextHighlighters.Add(highlighter);
}
private void btnRemoveHighlight_Click(object sender, RoutedEventArgs e)
{
Rtb.TextHighlighters.Clear();
}
提前谢谢..!
答案 0 :(得分:0)
这里的问题是TextPointer指向RTF结构。它不仅仅是字符串的纯文本版本的索引。富文本的组织方式如下:RichTextBlock具有一个Block集合,每个Block是一个具有Inline集合的Paragraph,并且每个Inline是Run(包含文本)或Span(包含Inline集合)或LineBreak(代表换行符)或InlineUIContainer(代表UI内容)。
RichTextBlock也表示为通过按顺序遍历此树而获得的序列。我们为每个元素的开头计算一个偏移量单位(可以认为是特殊字符),然后计算子元素或文本内容所需的偏移量单位,然后为该元素添加一个偏移量单位元素的关闭。方便地,TextPointer中的“偏移”是直至所选点的偏移单位数。
以下内容显示了如何遍历富文本并拾取TextPointer之前的文本。树中的每个元素都有ElementStart / ElementEnd指示其位置,而ContentStart / ContentEnd指示内容在其中的位置。字符串中包含位于TextPointer.Offset左侧的内容,例如Runs中的文本。警告:未经Linebreak或inlineUIContainer测试;不处理从右到左的文本;而且效率不高。
static class DocumentHelper
{
static public string TextUpTo(this InlineCollection inlines, TextPointer pointer)
{
StringBuilder textUpTo = new StringBuilder();
foreach (Inline inline in inlines) {
if (inline.ElementStart.Offset > pointer.Offset) {
break;
}
if (inline is Run run) {
// Need some more work here to take account of run.FlowDirection and pointer.LogicalDirection.
textUpTo.Append(run.Text.Substring(0, Math.Max(0, Math.Min(run.Text.Length, pointer.Offset - run.ContentStart.Offset))));
} else if (inline is Span span) {
string spanTextUpTo = span.Inlines.TextUpTo(pointer);
textUpTo.Append(spanTextUpTo);
} else if (inline is LineBreak lineBreak) {
textUpTo.Append((pointer.Offset >= lineBreak.ContentEnd.Offset) ? Environment.NewLine : "");
} else if (inline is InlineUIContainer uiContainer) {
textUpTo.Append(" "); // empty string replacing the UI content.
} else {
throw new InvalidOperationException($"Unrecognized inline type {inline.GetType().Name}");
}
}
return textUpTo.ToString();
}
static public string TextUpTo( this RichTextBlock rtb, TextPointer pointer)
{
StringBuilder textUpTo = new StringBuilder();
foreach (Block block in rtb.Blocks) {
if (block is Paragraph paragraph) {
textUpTo.Append(paragraph.Inlines.TextUpTo( pointer));
} else {
throw new InvalidOperationException($"Unrecognized block type {block.GetType().Name}");
}
}
return textUpTo.ToString();
}
}
现在…关于原始问题,我们可以这样处理:
private void BtnHighlight_Click(object sender, RoutedEventArgs e)
{
string textUpToStart = this.Rtb.TextUpTo(this.Rtb.SelectionStart);
string textUpToEnd = this.Rtb.TextUpTo(this.Rtb.SelectionEnd);
Debug.WriteLine($"Text up to start: '{textUpToStart}'; text up to end: '{textUpToEnd}'");
TextRange textRange = new TextRange { StartIndex = textUpToStart.Length, Length = (textUpToEnd.Length - textUpToStart.Length) };
TextHighlighter highlighter = new TextHighlighter() { Ranges = { textRange }, Background = new SolidColorBrush(Colors.Yellow) };
this.Rtb.TextHighlighters.Add(highlighter);
}
private void BtnRemoveHighlight_Click(object sender, RoutedEventArgs e)
{
this.Rtb.TextHighlighters.Clear();
}