Я использую AvalonEdit и хочу, чтобы пользователь всегда мог видеть, на какой строке находится курсор, даже если редактор не имеет фокуса. С этой целью я нашел и адаптировал некоторый код, который использует BackgroundRenderer для выделения фона текущей строки.
К сожалению, если я изменю CaretOffset, когда редактор не сфокусирован, мой фоновый прямоугольник останется на линии, которая была текущей, когда редактор потерял фокус. Он не синхронизируется с новой текущей строкой, пока редактор снова не получит фокус.
Я выяснил, почему это происходит (только не как это исправить). Согласно комментариям к документу для IBackgroundRenderer, «фоновый рендерер будет рисовать только в том случае, если связанный с ним известный слой решит их отрисовать. Например, фоновые рендереры в слое курсора будут невидимы, когда курсор скрыт». Мой фоновый рендеринг живет на KnownLayer.Caret, так что да, я понимаю, почему он не обновляется, когда редактор не сфокусирован — это потому, что курсор тоже скрыт. (Учитывая это, я действительно удивлен, что мой прямоугольник остается видимым.)
Я попытался явно вызвать textEditor.TextArea.TextView.InvalidateLayer(KnownLayer.Caret) сразу после того, как я установил CaretOffset, но это не дало никакого эффекта - я предполагаю, что вызов был проигнорирован, потому что каретка была скрыта.
Каков наилучший способ принудительно обновить выделение текущей строки, даже если редактор не имеет фокуса?
Вот код моего класса. Я, конечно, готов отказаться от этого и использовать другой подход, если есть лучший способ сделать это.
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));