在WPF中实现解析/可编辑Richtextbox的最佳方法

时间:2010-03-13 00:58:28

标签: wpf parsing input richtextbox

我正在尝试实现(最初作为原型),一个richtextbox控件,可以实时解析以应用某些格式化选项。这是在WPF中完成的,所以我认为最好的方法是扩展现有的富文本框控件。

我遇到的问题是它没有很好地记录,而且示例非常慢(我发现的那些在每次按键时解析了整个文档)。

我目前决定采用的方法是创建一个自定义的Inline元素,它可以保存格式化标签和内容。因此,我只需要解析当前段落和该段落中的运行以格式化标签。

有没有更好的方法来实现这一目标?请注意,这不适用于基于代码/语法的文档(因此AvalonEdit不合适)。

干杯

2 个答案:

答案 0 :(得分:4)

如果您可以定位.NET Framework 3.5及更高版本,则无需在每次更改时扫描文档:只需订阅TextChanged事件并使用TextChangedEventArgs.Changes属性获取更改列表。

每当收到TextChanged事件时,请遍历Changes集合并从Offset,AddedLength和RemovedLength构造TextRange。然后根据需要展开此TextRange以重新计算格式,然后执行格式计算并作为单独的步骤更新(在Dispatcher.BeginInvoke回调中),这样您就不会有递归的TextChanged事件。

richTextBox.TextChanged += (obj, e)
{
  var document = richTextBox.Document;
  var length = document.ContentStart.GetOffsetToPosition(document.ContentEnd);
  int totalAdd = 0;
  int totalRemove = 0;
  foreach(var change in e.Changes)
  {
    var expandBy = Math.Max(totalAdd,totalRemove);

    var startIndex = change.Offset - expandBy;
    var endIndex = changed.Offset + expandBy + Math.Max(totalAdd, totalRemove);

    startIndex = Math.Max(startIndex, 0);
    endIndex = Math.Min(endIndex, length);

    var startPointer = document.ContentStart.GetPositionAtOffset(startIndex);
    var endPointer = startPointer.GetPositionAtOffset(endIndex - startIndex);

    var range = new TextRange(startPointer, endPointer);
    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
    {
      DoParsingAndFormatting(ExpandRangeToUnitOfParsing(range));
    });
    totalAdd += change.AddedLength;
    totalRemove += change.RemovedLength;
  }
};

如果您想查找更改开始或结束的段落,可以使用range.Start.Paragraphrange.End.Paragraph

此外,对于许多情况,将文档中的所有文本的副本与FlowDocument本身分开存储会很有帮助。然后,当您对该文档应用更改时,您可以随时更新格式,而无需重新读取文档。请注意,文本不应存储在单个大型数组中,而应剪切成小块(可能大约1000个字符),并通过按索引组织片段的树进行访问。原因是在一个巨大的数组的开头插入一个字符是非常昂贵的。

答案 1 :(得分:-3)

CodeProject上查看此处。这篇文章可能会引起您对通过子类化扩展的RichTextBox控件感兴趣的文章...看看这个 - 具有更多功能的Extended RichTextBox控件