我正在尝试实现(最初作为原型),一个richtextbox控件,可以实时解析以应用某些格式化选项。这是在WPF中完成的,所以我认为最好的方法是扩展现有的富文本框控件。
我遇到的问题是它没有很好地记录,而且示例非常慢(我发现的那些在每次按键时解析了整个文档)。
我目前决定采用的方法是创建一个自定义的Inline元素,它可以保存格式化标签和内容。因此,我只需要解析当前段落和该段落中的运行以格式化标签。
有没有更好的方法来实现这一目标?请注意,这不适用于基于代码/语法的文档(因此AvalonEdit不合适)。
干杯
答案 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.Paragraph
和range.End.Paragraph
。
此外,对于许多情况,将文档中的所有文本的副本与FlowDocument本身分开存储会很有帮助。然后,当您对该文档应用更改时,您可以随时更新格式,而无需重新读取文档。请注意,文本不应存储在单个大型数组中,而应剪切成小块(可能大约1000个字符),并通过按索引组织片段的树进行访问。原因是在一个巨大的数组的开头插入一个字符是非常昂贵的。
答案 1 :(得分:-3)
在CodeProject上查看此处。这篇文章可能会引起您对通过子类化扩展的RichTextBox控件感兴趣的文章...看看这个 - 具有更多功能的Extended RichTextBox控件