簡體   English   中英

應用 TextWrapping 后如何獲得具有內聯元素支持的 TextBlock 行?

[英]How to get TextBlock lines with Inline element support after applying TextWrapping?

我試圖在包含 TextBlock 的幾個頁面上拆分一個很長的字符串(文檔),但是,我需要使每個頁面具有特定的行數,這意味着我需要將 TextBlock 拆分為行。

我試圖創建幾個邏輯,但沒有獲得准確的結果,但在這里找到了一個解決方案(根據 TextWrapping 屬性獲取 TextBlock 的行? )它在我的原型項目中對我有用,然后停止工作並獲取整個文本在一行中。

以下是上述主題的代碼:

public static class TextUtils
    {
        public static IEnumerable<string> GetLines(this TextBlock source)
        {
            var text = source.Text;
            int offset = 0;
            TextPointer lineStart = source.ContentStart.GetPositionAtOffset(1, LogicalDirection.Forward);
            do
            {
                TextPointer lineEnd = lineStart != null ? lineStart.GetLineStartPosition(1) : null;
                int length = lineEnd != null ? lineStart.GetOffsetToPosition(lineEnd) : text.Length - offset;
                yield return text.Substring(offset, length);
                offset += length;
                lineStart = lineEnd;
            }
            while (lineStart != null);
        }
    }

這是我的代碼:

<TextBlock x:Name="testTB" TextAlignment="Justify" FontFamily="Arial" FontSize="12" TextWrapping="Wrap" Width="100"/>
testTB.Text = Functions.GenString(200);

foreach (string xc in testTB.GetLines())
{
    MessageBox.Show(xc);
}

我猜問題是lineStart.GetLineStartPosition(1)正在返回null

任何幫助表示贊賞,提前致謝。

對我來說,您發布的代碼看起來容易出錯。 僅當TextBlock包含純文本時才有效。 但是,當您使用RunBoldUnderlineInline元素時,您將不再有純文本作為內容,還有上下文標記,例如內聯元素的標簽。 我想這是您基於偏移量的string.Substring失敗的地方。

解決方案是根據檢索到的TextPointer結果創建一個TextRange ,並通過TextRange.Text屬性提取純文本。

以下實現同時支持:通過TextBlock.Text屬性設置的純文本和使用Inline元素設置的文本:

public static IEnumerable<string> GetLines(this TextBlock source)
{
  TextPointer lineStart = source.ContentStart.GetPositionAtOffset(1, LogicalDirection.Forward);
  do
  {
    TextPointer lineEnd = lineStart.GetLineStartPosition(1) ?? source.ContentEnd; 
    var textRange = new TextRange(lineStart, lineEnd);
    lineStart = lineEnd;
    yield return textRange.Text;
  }
  while (lineStart.IsAtLineStartPosition);
}

評論

等待TextBlock.Loaded事件發生是很重要的。 這是因為TextBlockUIElement.Measure過程中將單個文本字符串拆分為多行,因為此時控件知道其所需大小,因此知道行的最大可用寬度。 UIElement.Measure在布局加載開始時由渲染引擎調用。

例子

主窗口.xaml

<Window>
  <TextBlock x:Name="TextBlock" 
             TextWrapping="Wrap"
             Width="100">
    <TextBlock.Inlines>
      <Run
        Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat," />
      <Bold>
        <Bold.Inlines>
          <Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, conse" />
        </Bold.Inlines>
      </Bold>
      <LineBreak />
      <LineBreak />
      <LineBreak />
      <Underline>
        <Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut " />
        <Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut " />
      </Underline>
      <Run Text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut " />
    </TextBlock.Inlines>
  </TextBlock>
</Window>

主窗口.xaml.cs

partial class MainWindow : Window
{
  public MainWindow()
  {
    this.Loaded += OnLoaded;
  }

  private void OnLoaded(object sender, EventArgs e)
  {
    var lines = this.TextBlock.GetLines().ToList(); // Returns 54 lines
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM