Страницы

Поиск по вопросам

четверг, 11 июля 2019 г.

WPF, Text Formatter API - Пример реализации абстрактного класса TextSource

Данный вопрос тесно связан с этим. Но ещё раз вкратце о реальной задаче: реализую текстовый редактор с поддержкой форматирования текста (выделение фрагмента текста, изменение гарнитуры его шрифта, размера и т.п.). Для решения сей задачи выбрал Text Formatter. Сейчас же меня интересует реализация текстового хранилища, для чего надо наследовать и реализовать абстрактный класс TextSource. Чтобы разобраться, как это сделать, хотелось бы увидеть какие-то примеры. Желательно, более сложные, нежели в официальном примере


Ответ

Ответ на вопрос получил на форуме MSDN - ссылка. Код примера привожу ниже:
class SampleTextSource : TextSource { string text = "Foo Bar
Next Line";
List spans = new List { new Span { Start = 0, Length = 3, Color = Brushes.Blue }, new Span { Start = 3, Length = 1, Color = Brushes.Black }, new Span { Start = 4, Length = 3, Color = Brushes.Red }, new Span { Start = 7, Length = 1, Color = Brushes.Black }, new Span { Start = 8, Length = 4, Color = Brushes.Green }, new Span { Start = 12, Length = 5, Color = Brushes.Black }, };
class Span { public int Start; public int Length; public Brush Color;
public bool Contains(int index) { return Start <= index && index < Start + Length; } }
public int Length { get { return text.Length; } }
public override TextRun GetTextRun(int textSourceCharacterIndex) { var span = spans.Find(s => s.Contains(textSourceCharacterIndex));
if (span == null) return new TextEndOfParagraph(1);
if (span.Length == 1 && text[span.Start] == '
') return new TextEndOfLine(1);
return new TextCharacters(text, span.Start, span.Length, new SampleTextRunProperties(span.Color)); }
public override TextSpan GetPrecedingText(int textSourceCharacterIndexLimit) { throw new NotImplementedException(); }
public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex(int textSourceCharacterIndex) { throw new NotImplementedException(); } }
class SampleTextRunProperties : TextRunProperties { private readonly Brush foregroundBrush;
public SampleTextRunProperties(Brush foregroundBrush) { this.foregroundBrush = foregroundBrush; } ...реализация остальных необходимых свойств (можно взять из SDK-примера) }
class SampleTextParagraphProperties : TextParagraphProperties { ...реализация остальных необходимых свойств (можно взять из SDK-примера) }
class SampleTextElement : UIElement { protected override void OnRender(DrawingContext drawingContext) { TextFormatter text = TextFormatter.Create(); SampleTextSource source = new SampleTextSource(); SampleTextParagraphProperties paraProps = new SampleTextParagraphProperties(); int index = 0; double y = 0.0;
while (index < source.Length) { TextLine line = text.FormatLine(source, index, RenderSize.Width, paraProps, null); line.Draw(drawingContext, new Point(0.0, y), InvertAxes.None); index += line.Length; y += line.TextHeight; } } }
SDK-пример можно скачать здесь
Если необходимо, чтобы текст отображался с переносом (а это зачастую и требуется), то нужно, во-первых, в реализации TextParagraphProperties переопределить свойство TextWrapping, а во-вторых, в реализации метода TextRun GetTextRun(int textSourceCharacterIndex) в последнем выражении return использовать следующий фрагмент кода, вместо выше приведённого:
return new TextCharacters(text, textSourceCharacterIndex, span.Length - (textSourceCharacterIndex - span.Start), new SampleTextRunProperties(span.Color));
Это делается для поддержки возможности разбивать span на несколько строк.

Комментариев нет:

Отправить комментарий