17

私はAvalonEditを使用していますが、エディターにフォーカスがない場合でも、ユーザーが常にカレットがどの行にあるかを確認できるようにしたいと考えています。そのために、BackgroundRendererを使用して現在の行の背景を強調表示するコードを見つけて適合させました。

残念ながら、エディターがフォーカスされていないときにCaretOffsetを変更すると、エディターがフォーカスを失ったときに現在の行に、背景の長方形が配置されたままになります。エディターが再びフォーカスを取得するまで、新しい現在の行に同期されません。

私はこれがなぜ起こっているのかを理解しました(それを修正する方法ではありません)。IBackgroundRendererのドキュメントコメントによると、「バックグラウンドレンダラーは、関連する既知のレイヤーが描画することを選択した場合にのみ描画します。たとえば、カレットレイヤーのバックグラウンドレンダラーは、カレットが非表示の場合は非表示になります。」私のバックグラウンドレンダラーはKnownLayer.Caretに存在するので、そうです、エディターがフォーカスされていないときに更新されない理由がわかります。これは、カレットも非表示になっているためです。(それを考えると、私の長方形が表示されたままであることに実際に驚いています。)

CaretOffsetを設定した直後にtextEditor.TextArea.TextView.InvalidateLayer(KnownLayer.Caret)を明示的に呼び出しようとしましたが、効果はありませんでした。キャレットが非表示になっているため、呼び出しは無視されたと思います。

エディターにフォーカスがない場合でも、現在の行のハイライトを強制的に更新するための最良の方法は何ですか?


これが私のクラスのコードです。私は確かにこれを捨てて、それを行うためのより良い方法があれば別のアプローチをすることにオープンです。

public class HighlightCurrentLineBackgroundRenderer : IBackgroundRenderer
{
    private TextEditor _editor;

    public HighlightCurrentLineBackgroundRenderer(TextEditor editor)
    {
        _editor = editor;
    }

    public KnownLayer Layer
    {
        get { return KnownLayer.Caret; }
    }

    public void Draw(TextView textView, DrawingContext drawingContext)
    {
        if (_editor.Document == null)
            return;

        textView.EnsureVisualLines();
        var currentLine = _editor.Document.GetLineByOffset(_editor.CaretOffset);
        foreach (var rect in BackgroundGeometryBuilder.GetRectsForSegment(textView, currentLine))
        {
            drawingContext.DrawRectangle(
                new SolidColorBrush(Color.FromArgb(0x40, 0, 0, 0xFF)), null,
                new Rect(rect.Location, new Size(textView.ActualWidth - 32, rect.Height)));
        }
    }
}

次に、UserControlのコンストラクターで、レンダラーをエディターに追加します。

textEditor.TextArea.TextView.BackgroundRenderers.Add(
    new HighlightCurrentLineBackgroundRenderer(textEditor));
4

1 に答える 1

17

これが私がこの作品を作ることになった方法です。

まず、HighlightCurrentLineBackgroundRendererのLayerプロパティを変更して、KnownLayer.Backgroundを返しました。エディターにフォーカスがない場合でも背景レイヤーが表示されるため、元の問題が解決します。

ただし、新しい問題が発生します。背景レイヤーは特定の条件下でのみ再描画され、「キャレット移動」はそのような条件の1つではないため、ハイライトはまったく移動しません。(たとえば、スクロールしたり、テキストを選択したりすると、そうなります。しかし、それは望ましい動作ではありません。)しかし、それは簡単に解決できます。カレットが動くたびに、背景レイヤーを手動で無効にする必要があります。

textEditor.TextArea.Caret.PositionChanged += (sender, e) =>
    textEditor.TextArea.TextView.InvalidateLayer(KnownLayer.Background);

これですべてです。エディターがフォーカスされていなくても、ハイライトが更新されるようになりました。

于 2011-02-23T02:40:55.777 に答える