2017-02-06 1 views
1

J'utilise actuellement le code suivant comme LineTransformer avec un AvalonEdit TextEditor. Je veux être en mesure de mettre en évidence le résultat de recherche unique actuel avec une sélection, mais la sélection est à peine visible car le formatage du DocumentColorizingTransformer a préséance sur le texte en surbrillance. Comment puis-je obtenir la sélection en surbrillance à afficher au lieu ou avant le formatage?AvalonEdit afficher la sélection sur autre formatage

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++; 
     } 
    } 
} 

Example of formatting showing over selection

Répondre

0

Alors, voici mon produit final basé presque entièrement hors de la AvalonEdit existante SearchResultBackgroundRenderer.

Cela fonctionne un peu différemment du coloriseur de mon article, car vous devez modifier les résultats manuellement au lieu de le faire pour vous. Mais cela peut aussi économiser du temps de calcul.

Si votre recherche n'utilise pas Regex, alors vous pouvez facilement modifier SearchResult pour passer simplement un offset de début et une longueur pour le constructeur.

/// <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; } 
} 

Afin d'utiliser le moteur de rendu de fond:

var searchColorizor = new ColorizeSearchResultsBackgroundRenderer(); 
textEditor.TextArea.TextView.BackgroundRenderers.Add(searchColorizor); 
1

Voir http://avalonedit.net/documentation/html/c06e9832-9ef0-4d65-ac2e-11f7ce9c7774.htm pour AvalonEdit rendre le flux.

La couche de sélection est rendue avant le texte. Donc, si le texte a un arrière-plan, il remplace l'arrière-plan de sélection. Heureusement, nous pouvons définir l'arrière-plan à Brush.Transparent (ou un mélange de Selection.Brush et votre propre couleur).

Solution: J'ai modifié le code SelectionColorizer pour réinitialiser fond de sélection transparent:

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); 
        } 
       }); 
     } 
    } 
} 

Pour utiliser le code que vous êtes censé faire ce qui suit:

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)); 
1

Après ai essayé mes solutions intensivement, je voudrais ajouter quelques points:

  • Alors que mon autre solu ci-dessus semble fonctionner, vous aurez quelques artefacts subpixel lorsque les rectangles sont censés être carrelés. Si cela n'est pas acceptable, vous pouvez implémenter un IBackgroundRenderer. (Cela se trouve être ma solution choisie.) Si vous voulez du code, vous pouvez demander ici, mais je doute que ce soit utile.

  • BTW, depuis votre question est sur le résultat de recherche, le plus probable que vous pouvez utiliser https://github.com/icsharpcode/AvalonEdit/blob/697ff0d38c95c9e5a536fbc05ae2307ec9ef2a63/ICSharpCode.AvalonEdit/Search/SearchResultBackgroundRenderer.cs non modifié (ou le modifier si vous ne voulez pas les bordures arrondies). Vous pouvez utiliser element.BackgroundBrush = Brushes.Magenta; au lieu de element.TextRunProperties.SetBackgroundBrush(Brushes.Magenta);. AvalonEdit semble dessiner l'arrière-plan avec un rectangle avec 3px radius.

  • Il existe également un RichTextColorizer à partir d'AvalonEdit 5.01. Je ne sais pas comment l'utiliser car il n'est pas référencé dans d'autres fichiers. Et les rectangles arrondis (le plus probablement indésirable) dans le paragraphe précédent sont susceptibles d'être présents.

+0

je suis revenu à cette question un an plus tard avec un programme différent et essayé le 'IBackgroundRenderer'. Cela a fonctionné parfaitement autrement que le fait que les rectangles dessinés étaient légèrement plus grands que les rectangles de sélection mais pas un gros problème. –

+0

Apparemment, enlever le pinceau du surligneur a même corrigé ce problème mineur. –