[英]AvalonEdit show selection over other formatting
我目前正在使用以下代碼作為AvalonEdit TextEditor
的LineTransformer
。 我希望能夠通過選擇突出顯示當前的單個搜索結果,但是該選擇幾乎不可見,因為DocumentColorizingTransformer
的格式優先於顯示突出顯示的文本。 如何顯示突出顯示的選擇內容而不是顯示格式?
public class ColorizeSearchResults : DocumentColorizingTransformer {
public ColorizeSearchResults() : base() {
SearchTerm = "";
MatchCase = false;
}
public string SearchTerm { get; set; }
public bool MatchCase { get; set; }
protected override void ColorizeLine(DocumentLine line) {
if (SearchTerm.Length == 0)
return;
int lineStartOffset = line.Offset;
string text = CurrentContext.Document.GetText(line);
int count = 0;
int start = 0;
int index;
while ((index = text.IndexOf(SearchTerm, start, MatchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) >= 0) {
base.ChangeLinePart(
lineStartOffset + index,
lineStartOffset + index + SearchTerm.Length,
(VisualLineElement element) => {
element.TextRunProperties.SetForegroundBrush(Brushes.White);
element.TextRunProperties.SetBackgroundBrush(Brushes.Magenta);
});
start = index + 1;
count++;
}
}
}
有關AvalonEdit渲染流程,請參見http://avalonedit.net/documentation/html/c06e9832-9ef0-4d65-ac2e-11f7ce9c7774.htm 。
選擇層在文本之前呈現。 因此,如果文本具有背景,它將覆蓋選擇背景。 幸運的是,我們可以將背景設置為Brush.Transparent(或Selection.Brush和您自己的顏色的混合)。
解決方案:我已經修改了SelectionColorizer代碼,以將選擇背景重置為透明:
class SelectionColorizerWithBackground : ColorizingTransformer
{
ICSharpCode.AvalonEdit.Editing.TextArea _textArea;
public SelectionColorizerWithBackground(
ICSharpCode.AvalonEdit.Editing.TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
this._textArea = textArea;
}
protected override void Colorize(ITextRunConstructionContext context)
{
int lineStartOffset = context.VisualLine.FirstDocumentLine.Offset;
int lineEndOffset = context.VisualLine.LastDocumentLine.Offset +
context.VisualLine.LastDocumentLine.TotalLength;
foreach (var segment in _textArea.Selection.Segments)
{
int segmentStart = segment.StartOffset;
if (segmentStart >= lineEndOffset)
continue;
int segmentEnd = segment.EndOffset;
if (segmentEnd <= lineStartOffset)
continue;
int startColumn;
if (segmentStart < lineStartOffset)
startColumn = 0;
else
startColumn = context.VisualLine.ValidateVisualColumn(
segment.StartOffset, segment.StartVisualColumn,
_textArea.Selection.EnableVirtualSpace);
int endColumn;
if (segmentEnd > lineEndOffset)
endColumn =
_textArea.Selection.EnableVirtualSpace
? int.MaxValue
: context.VisualLine
.VisualLengthWithEndOfLineMarker;
else
endColumn = context.VisualLine.ValidateVisualColumn(
segment.EndOffset, segment.EndVisualColumn,
_textArea.Selection.EnableVirtualSpace);
ChangeVisualElements(
startColumn, endColumn,
element => {
element.TextRunProperties.SetBackgroundBrush(
System.Windows.Media.Brushes.Transparent);
if (_textArea.SelectionForeground != null)
{
element.TextRunProperties.SetForegroundBrush(
_textArea.SelectionForeground);
}
});
}
}
}
要使用該代碼,您應該執行以下操作:
var lineTransformers = textEditor.TextArea.TextView.LineTransformers;
// Remove the original SelectionColorizer.
// Note: if you have syntax highlighting you need to do something else
// to avoid clearing other colorizers. If too complicated you can skip
// this step but to suffer a 2x performance penalty.
lineTransformers.Clear();
lineTransformers.Add(new ColorizeSearchResults());
lineTransformers.Add(
new SelectionColorizerWithBackground(textEditor.TextArea));
在廣泛嘗試了解決方案之后,我想補充幾點:
盡管上面的其他解決方案似乎可行,但是當應該將矩形平鋪時,會有一些亞像素偽像。 如果不可接受,則可以實現IBackgroundRenderer。 (這恰好是我選擇的解決方案。)如果您想要一些代碼,可以在這里請求,但是我懷疑它是否有用。
順便說一句, 由於您的問題是關於搜索結果的 , 因此最有可能使用未經修改的https://github.com/icsharpcode/AvalonEdit/blob/697ff0d38c95c9e5a536fbc05ae2307ec9ef2a63/ICSharpCode.AvalonEdit/Search/Search/SearchResultBackgroundRenderer.cs (如果您不進行修改,則可以對其進行修改)想要圓角邊框)。
您可以使用element.BackgroundBrush = Brushes.Magenta;
而不是element.TextRunProperties.SetBackgroundBrush(Brushes.Magenta);
。 AvalonEdit似乎使用3px半徑的矩形繪制背景。
從AvalonEdit 5.01開始還有RichTextColorizer。 我不知道如何使用它,因為在其他文件中未引用它。 並且上一段中(最可能不需要的)圓角矩形很可能會出現。
因此,這是我的最終產品,幾乎完全基於現有的AvalonEdit SearchResultBackgroundRenderer
。
這與我帖子的着色器有些不同,因為您必須手動修改搜索結果,而不是為您自己做。 但這也可以節省一些計算時間。
如果您的搜索未使用Regex,則可以輕松地修改SearchResult,而只需為構造函數傳遞起始偏移量和長度。
/// <summary>A search result storing a match and text segment.</summary>
public class SearchResult : TextSegment {
/// <summary>The regex match for the search result.</summary>
public Match Match { get; }
/// <summary>Constructs the search result from the match.</summary>
public SearchResult(Match match) {
this.StartOffset = match.Index;
this.Length = match.Length;
this.Match = match;
}
}
/// <summary>Colorizes search results behind the selection.</summary>
public class ColorizeSearchResultsBackgroundRenderer : IBackgroundRenderer {
/// <summary>The search results to be modified.</summary>
TextSegmentCollection<SearchResult> currentResults = new TextSegmentCollection<SearchResult>();
/// <summary>Constructs the search result colorizer.</summary>
public ColorizeSearchResultsBackgroundRenderer() {
Background = new SolidColorBrush(Color.FromRgb(246, 185, 77));
Background.Freeze();
}
/// <summary>Gets the layer on which this background renderer should draw.</summary>
public KnownLayer Layer {
get {
// draw behind selection
return KnownLayer.Selection;
}
}
/// <summary>Causes the background renderer to draw.</summary>
public void Draw(TextView textView, DrawingContext drawingContext) {
if (textView == null)
throw new ArgumentNullException("textView");
if (drawingContext == null)
throw new ArgumentNullException("drawingContext");
if (currentResults == null || !textView.VisualLinesValid)
return;
var visualLines = textView.VisualLines;
if (visualLines.Count == 0)
return;
int viewStart = visualLines.First().FirstDocumentLine.Offset;
int viewEnd = visualLines.Last().LastDocumentLine.EndOffset;
foreach (SearchResult result in currentResults.FindOverlappingSegments(viewStart, viewEnd - viewStart)) {
BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder();
geoBuilder.AlignToWholePixels = true;
geoBuilder.BorderThickness = 0;
geoBuilder.CornerRadius = 0;
geoBuilder.AddSegment(textView, result);
Geometry geometry = geoBuilder.CreateGeometry();
if (geometry != null) {
drawingContext.DrawGeometry(Background, null, geometry);
}
}
}
/// <summary>Gets the search results for modification.</summary>
public TextSegmentCollection<SearchResult> CurrentResults {
get { return currentResults; }
}
/// <summary>Gets or sets the background brush for the search results.</summary>
public Brush Background { get; set; }
}
為了使用背景渲染器:
var searchColorizor = new ColorizeSearchResultsBackgroundRenderer();
textEditor.TextArea.TextView.BackgroundRenderers.Add(searchColorizor);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.