2017-01-24 56 views
0

在UWP应用程序中,我正在使用RichTextBlock获取一些内容。它启用了换行功能,并设置了最大行数,以便不管内容的长度如何,它只会显示一定数量的富文本行。从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> 

我想知道有多少文本实际上是可见的。

我试图检测文本比设定的行数多的情况,并在最后一行的末尾添加“... Read More”(用最后的13个字符替换“...阅读更多“)

+0

您必须使用“...阅读更多”? “......”可以吗? – Scavenger

+0

是的,它必须是“...阅读更多”,否则我会刚刚使用TextTrimming = CharacterEllipsis 不幸的是,没有办法提供使用自定义文本来代替“...”使用TextTrimming时,它将解决我的问题。 –

回答

1

所以我写了一些代码来获得我想要的行为,但不幸的是这是相当慢和低效率。因此,如果您在主要用于显示大量需要截断的文本的应用程序中使用它(例如具有大量文本项目的ListView),那么这会降低您的应用程序性能。我仍然想知道是否有更好的方法来做到这一点。

这里是我的代码(仅处理运行和超链接的内联函数,所以你必须修改来处理,你需要其他类型):

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; 
      } 
     } 
    } 
}