如何使用现有内容格式化RichTextBox

时间:2019-07-10 19:40:08

标签: c# wpf formatting richtextbox

我正在从Web API获取数据,该API返回文本并格式化信息。格式数据仅包括格式类型(粗体,斜体等)和该格式的范围。这样做的主要问题是,两个范围可以“冲突”(例如,单词的前3个字符为粗体和斜体,而后3个字符仅为斜体)。响应示例

{
  "text" : "This is an example text",
  "inlineStyles" : [
    {
      "offsetFromStart" : 5,
      "length" : 10,
      "type" : "bold"
    }
    {
      "offsetFromStart" : 10,
      "length" : 10,
      "type" : "italic"
    }
  ]
}

我已经尝试使用简单的TextBlock进行此操作,但失败了。我也使用RichTextBox进行了尝试,但是当我添加Span时,无法将其插入其原始位置。我也很难用自己的跨度或运行来格式化每个字符,但这将是非常丑陋的,并且通常只是一个不好的解决方案。 (我主要关心的是速度。)

var tb = new RichTextBox();
var para = new Paragraph();
para.Inlines.Add("This is an example text") // Text parsed from the response

var startingPointer1 = para.ContentStart.GetPositionAtOffset(5);
var sp1 = new Span(startingPointer1, startingPointer1.GetPositionAtOffset(10));
sp1.FontWeight = FontWeights.Bold;

var startingPointer2 = para.ContentStart.GetPositionAtOffset(10);
var sp2 = new Span(startingPointer2 , startingPointer2 .GetPositionAtOffset(10));
sp2.FontStyle= FontStyles.Italic;

para.Inlines.Add(sp1);
para.Inlines.Add(sp2);
tb.Document.Blocks.Add(para);

此代码将其追加到末尾,并且在组合多个内联元素时(如我的示例),它根本不起作用(因为第一个问题。)

示例结果:example image

2 个答案:

答案 0 :(得分:1)

我不认为您可以像这样重叠运行/跨度,您将不得不在文本中找到所有断点并分别设置每个文本范围的格式。它类似于HTML,其中

<bold>some<italic> bold italic</bold> and other </italic> text.

无效。就您而言,您将使用(5,10)的粗体,(11,15)的粗体等。

找到某种Range类并使用方法来组合范围,拆分,查找重叠等可能很有用。前一段时间,我从this开始。

编辑:我完全不知道如何实现所有这些(上一次我做类似的事情是在10年前),但是您可以尝试这样的事情:

  1. 创建一个List<Range<int>>。最初它包含一个Range(0,文本长度)。
  2. 加载第一个样式,创建一个具有开始/结束偏移量的新Range。将该范围与列表中的范围重叠(或任何合适的方法)。这应该为您提供3个范围,例如(0, start of style), (start of style, end of style), (end of style, end of text)。从列表中删除旧范围,然后添加新范围。
  3. 加载下一个,找到重叠区域,并在列表中列出范围,删除重叠区域并添加新范围。
  4. 这应该为您提供不重叠范围的列表。
  5. 现在,为样式。您可以创建一种样式表类。此类可以使用FontWeights, FontStyles中定义的System.Windows和其他枚举。修改列表,使其包含例如List<Tuple<int, Stylesheet>>。要计算重叠,只需使用元组中的第一个参数即可。
  6. 在从列表中删除旧范围之前,请组合样式。
  7. 这应该为您提供不重叠区域的列表以及适当的样式。创建TextRange,应用样式

其他可行的想法:

  1. 同样,创建一个样式表。最初应该是普通的重量,常规样式,默认字体大小等。
  2. 找到输入的下一个偏移量(第一个大于当前偏移量),创建一个TextRange并应用样式。
  3. 从输入中查找下一个偏移量,修改当前(且仅)样式并应用。

如果我没记错的话,在文本中插入样式定义也算作字符,因此,在最终文本中插入样式标签时,可能需要调整偏移量。另外,我相信仅使用TextBlock就可以。

正如我所说,我不知道这是否如描述的那样工作,但这可能会给您和想法。

答案 1 :(得分:0)

我当前的解决方案是我逐个浏览每个字符,并扫描范围以检测当前字符是否在每个字符中,然后为该字符分配一个跨度。这完全不是理想,但是可以完成工作。稍后,我将尝试实现一种实际的算法。在此之前,如果您有任何信息可能会有所帮助,请发表评论。

如果有人需要我当前实施的示例代码,我很乐意与您分享。 (即使它根本不是很有效)