2017-01-24 22 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 с большим количеством текстовых элементов), это замедлит ваше приложение perf. Я все еще хотел бы знать, есть ли лучший способ сделать это.

Вот мой код (который обрабатывает только Run и гиперссылка Внутристрочным, поэтому вам придется изменить для обработки других типов, которые вам нужны):

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

 Смежные вопросы

  • Нет связанных вопросов^_^