在UWP应用中,我使用的RichTextBlock会填充一些内容。它启用了自动换行功能,并设置了最大行数,这样无论内容的长度如何,它都只会显示一定数量的富文本行。
我想知道是否有办法弄清楚什么是可见文字?
所以,如果我有:
<RichTextBlock TextWrapping="Wrap" MaxLines="2">
<RichTextBlock.Blocks>
<Paragraph>
<Paragraph.Inlines>
A bunch of runs go in here with text that are several lines
</Paragraph.Inlines>
</Paragraph>
</RichTextBlock.Blocks>
</RichTextBlock>
我想知道有多少文字实际可见。
我试图检测文本长度超过设定行数的情况并添加&#34; ...阅读更多&#34;在最后一行的末尾(用&#34替换最后13个字符; ...阅读更多&#34;)
答案 0 :(得分:1)
所以我写了一些代码来获取我想要的行为,但不幸的是,这是相当缓慢和低效的。因此,如果您在主要显示大量需要截断的文本的应用程序中使用它(如带有大量文本项的ListView),那么这会降低您的应用程序性能。我仍然想知道是否有更好的方法来做到这一点。
这是我的代码(只处理Run和Hyperlink内联,所以你必须修改以处理你需要的其他类型):
private static void TrimText_Slow(RichTextBlock rtb)
{
var paragraph = rtb?.Blocks?.FirstOrDefault() as Paragraph;
if (paragraph == null) { return; }
// Ensure RichTextBlock has passed a measure step so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
if (rtb.HasOverflowContent == false) { return; }
// Start from end and remove all inlines that are not visible
Inline lastInline = null;
var idx = paragraph.Inlines.Count - 1;
while (idx >= 0 && rtb.HasOverflowContent)
{
lastInline = paragraph.Inlines[idx];
paragraph.Inlines.Remove(lastInline);
idx--;
// Ensure RichTextBlock has passed a measure step now with an inline removed, so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
}
// The last inline could be partially visible. The easiest thing to do here is to always
// add back the last inline and then remove characters from it until everything is in view.
if (lastInline != null)
{
paragraph.Inlines.Add(lastInline);
}
// Make room to insert "... Read More"
DeleteCharactersFromEnd(paragraph.Inlines, 13);
// Insert "... Continue Reading"
paragraph.Inlines.Add(new Run { Text = "... " });
paragraph.Inlines.Add(new Run { Text = "Read More", Foreground = new SolidColorBrush(Colors.Blue) });
// Ensure RichTextBlock has passed a measure step now with the new inlines added, so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
// Keep deleting chars until "... Continue Reading" comes into view
idx = paragraph.Inlines.Count - 3; // skip the last 2 inlines since they are "..." and "Read More"
while (idx >= 0 && rtb.HasOverflowContent)
{
Run run;
if (paragraph.Inlines[idx] is Hyperlink)
{
run = ((Hyperlink)paragraph.Inlines[idx]).Inlines.FirstOrDefault() as Run;
}
else
{
run = paragraph.Inlines[idx] as Run;
}
if (string.IsNullOrEmpty(run?.Text))
{
paragraph.Inlines.Remove(run);
idx--;
}
else
{
run.Text = run.Text.Substring(0, run.Text.Length - 1);
}
// Ensure RichTextBlock has passed a measure step now with the new inline content updated, so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
}
}
private static void DeleteCharactersFromEnd(InlineCollection inlines, int numCharsToDelete)
{
if (inlines == null || inlines.Count < 1 || numCharsToDelete < 1) { return; }
var idx = inlines.Count - 1;
while (numCharsToDelete > 0)
{
Run run;
if (inlines[idx] is Hyperlink)
{
run = ((Hyperlink)inlines[idx]).Inlines.FirstOrDefault() as Run;
}
else
{
run = inlines[idx] as Run;
}
if (run == null)
{
inlines.Remove(inlines[idx]);
idx--;
}
else
{
var textLength = run.Text.Length;
if (textLength <= numCharsToDelete)
{
numCharsToDelete -= textLength;
inlines.Remove(inlines[idx]);
idx--;
}
else
{
run.Text = run.Text.Substring(0, textLength - numCharsToDelete);
numCharsToDelete = 0;
}
}
}
}