C# 应用TextWrapping后,如何获得具有内联元素支持的TextBlock行?

C# 应用TextWrapping后,如何获得具有内联元素支持的TextBlock行?,c#,wpf,textblock,C#,Wpf,Textblock,我试图将一个很长的字符串(文档)拆分为包含TextBlock的几页,但是,我需要使每一页都有特定的行数,这意味着我需要将TextBlock拆分为行 我试图创建几个逻辑,但没有得到一个准确的东西,但在这里找到了一个解决方案(),它在我的原型项目中对我有效,然后停止工作,并在一行中获得整个文本 以下是上述主题的代码: 公共静态类TextUtils { 公共静态IEnumerable GetLines(此文本块源) { var text=source.text; 整数偏移=0; text指针lineS

我试图将一个很长的字符串(文档)拆分为包含TextBlock的几页,但是,我需要使每一页都有特定的行数,这意味着我需要将TextBlock拆分为行

我试图创建几个逻辑,但没有得到一个准确的东西,但在这里找到了一个解决方案(),它在我的原型项目中对我有效,然后停止工作,并在一行中获得整个文本

以下是上述主题的代码:

公共静态类TextUtils
{
公共静态IEnumerable GetLines(此文本块源)
{
var text=source.text;
整数偏移=0;
text指针lineStart=source.ContentStart.GetPositionAtOffset(1,LogicalDirection.Forward);
做
{
text指针lineEnd=lineStart!=null?lineStart.GetLineStartPosition(1):null;
int length=lineEnd!=null?lineStart.getOffsetPosition(lineEnd):text.length-offset;
产生返回文本。子字符串(偏移量、长度);
偏移量+=长度;
lineStart=lineEnd;
}
while(lineStart!=null);
}
}
这是我的代码:

<TextBlock x:Name="testTB" TextAlignment="Justify" FontFamily="Arial" FontSize="12" TextWrapping="Wrap" Width="100"/>
我猜问题是
lineStart.GetLineStartPosition(1)
正在返回null


感谢您提供的任何帮助。

对我来说,您发布的代码看起来很容易出错。仅当
TextBlock
包含纯文本时,它才起作用。但是当您使用
内联
元素(如
运行
粗体
下划线
)时,您不再使用纯文本作为内容,而是使用上下文标记(如内联元素的标记)。我想这就是基于偏移量的
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);
}
MainWindow.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
  }
}

这几乎没有开放式的限制。这个文本块的来源是什么?您是否考虑了用户界面的宽度和长度,因为文本块可能因用户界面(无论是windows还是web)的不同而有所不同。您是否研究了文本块中滚动条的使用选项,或者您的工作的理想意图是什么?文本源存储在数据库中,为了简单起见,让我们假设GenString函数生成随机字符串。TextBlock大小是静态的,在运行时字符串确实被包装成行。不,我不想使用滚动条。我试图实现的是用文本填充TextBlock,直到有一定数量的行(代表我需要的高度),然后在另一个页面中填充剩余的文本。
TextBlock
没有这种API,因为它是为单行文本设计和优化的。当切换到只读
文本框时,您可以使事情变得更简单。它提供了您需要的所有API。另一个解决方案是使用该类来测量文本宽度,并自己计算换行符。好吧,上面的代码曾经在文本块上为其他人工作过。然而,我考虑过文本框,但据我所知,它们不提供使用内联粗体和下划线格式化内部内容的功能。我并不是说它不起作用。我只是建议使用
TextBox
,因为它提供了一个简单的API来获取行数或实际行数。您发布的代码是一个简单的迭代。它不起作用的唯一原因是
TextBlock
bI的内容确实会面临内联线和格式的问题,但现在我甚至不能使用纯文本,因为某些原因,我尝试了你的代码,但也不起作用。。。同一问题,函数将所有文本作为一行输出。你能给我一个完整的工作示例吗?也许我的xaml或文本分配方法有问题,也许你能给我一个xaml代码片段和用法示例。很抱歉,我给您带来了麻烦…将字符串指定给
TextBlock.Text
时,您会犯什么错误。我不确定你是不是认真的。尽管如此,我还是添加了我刚刚用来测试它的代码。该方法返回54行。您发布的
GetLines
实现与示例输入一起崩溃。好吧,欢迎您。请记住,除非加载了相关控件,否则不要执行任何操作<代码>文本块
将在
ui元素期间应用换行。测量
计算。此方法仅在加载布局时触发。因为只有在这里,控件才知道其所需的渲染大小,并且可以相应地分割字符串。在此之前,
TextBlock
只包含一个文本字符串。或者将
Dispatcher.InvokeAsync
DispatcherPriority.Loaded一起使用。但这将在加载当前调度程序的完整作用域(线程)后执行,而当前调度程序大部分时间是主线程。在这种情况下,这将等于加载了应用程序。对于您的场景,您可以订阅
TextBlock.Loaded
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
  }
}