因此,我正在尝试为RichTextBox中的所有正则表达式匹配项(“标记”)着色。我已经写了这段代码:
MatchCollection mac;
private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (RichTextBox.IsFocused)
{
if (new TextRange(RichTextBox.Document.ContentStart, RichTextBox.Document.ContentEnd).Text != null)
{
// get all tags
mac = Regex.Matches(new TextRange(RichTextBox.Document.ContentStart, RichTextBox.Document.ContentEnd).Text, @"\<(.+?)\>");
//change the color of tags
this.Title = mac.OfType<Match>().Select(r => colorer(r)).Count().ToString() + " Was found I colored";
}
}
}
int w = 1;
private Match colorer(Match ma)
{
TextPointer start = new TextRange(RichTextBox.Document.ContentStart, RichTextBox.Document.ContentEnd).Start.GetPositionAtOffset(ma.Index);
TextPointer end = start.GetPositionAtOffset(ma.Length);
TextRange te = new TextRange(start, end);
te.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
list1.Items.Add(ma.Value + ":" + ma.Index + " : " + ma.Length + " teksti: " + te.Text + " : " + (ma.Length + ma.Index));
RichTextBox.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Black));
return ma;
}
这是第一个正确着色的标签,但所有其他标签的着色都不正确
您的问题是TextRange
的每个高亮在内部创建一个新的Run
,以更改跨度的字体颜色。这意味着将标签添加到文档的内容。因此,随着文本位置的移动,匹配项的索引不再有效。
您可以通过将标签长度乘以匹配索引来添加插入标签的偏移量,但这很容易出错,尤其是在允许用户格式化文本时。
通常,您的解决方案最糟糕,因为性能很差。您正在以较高的比率应用正则表达式。但是,要替换od [Regex
]并重新使用它,您总是要创建一个新对象。您应该重用单个Regex
实例:
private ReusableRegex {get;} = new Regex("<(.+?)>", RegexOptions.Compiled);
但是主要问题是您要根据每个击键上的模式匹配complete输入。一遍又一遍地。甚至先前匹配的范围也会重新评估,并再次创建一个新的TextRange
,并且设置了Foreground
会强制渲染RichTextBox
。我不知道您的文档大小,但是很快就会变得很糟。 RichTextBox
已经足够重。
您应该只评估当前输入。
下面的示例仅检查定界符的存在。该算法将忽略内容。找到起始定界符“ ”以查找有效令牌。您可以对此进行改进通过将规则应用于实际令牌的内容或检测文本删除,例如删除定界符。这比使用正则表达式并在每次击键时扫描和格式化整个文档要有效得多。
MainWindow.xaml
<Window>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<RichTextBox TextChanged="RichTextBox_TextChanged" />
<ListView Grid.Column="1"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=MainWindow}, Path=Results}" />
</Grid>
</Window>
MainWindow.xaml.cs
public static readonly DependencyProperty ResultsProperty = DependencyProperty.Register(
"Results",
typeof(ObservableCollection<string>),
typeof(MainWindow),
new PropertyMetadata(default(ObservableCollection<string>)));
public ObservableCollection<string> Results
{
get => (ObservableCollection<string>) GetValue(MainWindow.ResultsProperty);
set => SetValue(MainWindow.ResultsProperty, value);
}
private int TagStartOffset { get; set; }
private int TotalMatchCount { get; set; }
public MainWindow()
{
this.Results = new ObservableCollection<string>();
}
private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var richTextBox = sender as RichTextBox;
var changeOffset = e.Changes.ToList().LastOrDefault()?.Offset ?? 0;
string input = richTextBox.Document
.ContentStart
.GetPositionAtOffset(changeOffset, LogicalDirection.Forward)
.GetInsertionPosition(LogicalDirection.Forward)
.GetTextInRun(LogicalDirection.Forward);
// Check if input could be a tag. If true store offset.
if (input.StartsWith("<"))
{
this.TagStartOffset = changeOffset;
return;
}
// If there was a starting tag found and current input is a closing tag
// then highlight the range
if (this.TagStartOffset > -1 && input.StartsWith(">"))
{
var matchingTextRanged =
new TextRange(
richTextBox.Document
.ContentStart
.GetPositionAtOffset(this.TagStartOffset)
.GetInsertionPosition(LogicalDirection.Forward),
richTextBox.Document
.ContentStart
.GetPositionAtOffset(changeOffset, LogicalDirection.Forward)
.GetNextInsertionPosition(LogicalDirection.Forward));
HighLightTextRange(matchingTextRanged);
ResetTextColor(richTextBox);
CreateOverView(matchingTextRanged);
this.TagStartOffset = -1;
this.TotalMatchCount++;
}
this.Title = $"Found and colored {this.TotalMatchCount} tags";
}
private void HighLightTextRange(TextRange textRange) =>
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
private void CreateOverView(TextRange textRange) => this.Results.Add(
$"{matchingTextRanged.Text}: {this.TagStartOffset}: {matchingTextRanged.Text.Length} teksti: {matchingTextRanged.Text}: {matchingTextRanged.Text.Length + this.TagStartOffset}");
private ResetTextColor(RichTextBox richTextBox) => richTextBox.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Black));