Лучший способ реализовать Parsing / Editable Richtextbox в WPF - PullRequest
4 голосов
/ 13 марта 2010

Я пытаюсь реализовать (изначально как прототип) элемент управления richtextbox, который можно анализировать в реальном времени, чтобы применить к нему определенные параметры форматирования. Это делается в WPF, поэтому я подумал, что лучший способ сделать это - расширить существующий элемент управления rich text box.

Я столкнулся с проблемой, когда она плохо документирована, и примеры довольно медленные (те, которые я нашел, анализируют весь документ при каждом нажатии клавиши).

В настоящее время я решил использовать собственный встроенный элемент, который может содержать теги форматирования и содержимое. Поэтому мне нужно только проанализировать текущий абзац и прогоны в этом абзаце для форматирования тегов.

Есть ли лучший способ добиться этого? Обратите внимание, что это не для документов на основе кода / синтаксиса (поэтому AvalonEdit не подходит).

Приветствия

Ответы [ 2 ]

4 голосов
/ 13 марта 2010

Если вы можете использовать NET Framework 3.5 и выше, вам не нужно сканировать документ при каждом изменении: просто подпишитесь на событие TextChanged и используйте свойство TextChangedEventArgs.Changes, чтобы получить список изменений.

Всякий раз, когда вы получаете событие TextChanged, перебирайте коллекцию Changes и создайте TextRange из Offset, AddedLength и RemovedLength. Затем разверните этот TextRange соответствующим образом для пересчета форматирования, затем выполните вычисление форматирования и обновите его как отдельный шаг (в обратном вызове Dispatcher.BeginInvoke), чтобы у вас не было рекурсивных событий TextChanged.

richTextBox.TextChanged += (obj, e)
{
  var document = richTextBox.Document;
  var length = document.ContentStart.GetOffsetToPosition(document.ContentEnd);
  int totalAdd = 0;
  int totalRemove = 0;
  foreach(var change in e.Changes)
  {
    var expandBy = Math.Max(totalAdd,totalRemove);

    var startIndex = change.Offset - expandBy;
    var endIndex = changed.Offset + expandBy + Math.Max(totalAdd, totalRemove);

    startIndex = Math.Max(startIndex, 0);
    endIndex = Math.Min(endIndex, length);

    var startPointer = document.ContentStart.GetPositionAtOffset(startIndex);
    var endPointer = startPointer.GetPositionAtOffset(endIndex - startIndex);

    var range = new TextRange(startPointer, endPointer);
    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
    {
      DoParsingAndFormatting(ExpandRangeToUnitOfParsing(range));
    });
    totalAdd += change.AddedLength;
    totalRemove += change.RemovedLength;
  }
};

Если вы хотите найти абзац, где изменение начинается или заканчивается, вы можете использовать range.Start.Paragraph и range.End.Paragraph.

Кроме того, для многих ситуаций будет полезно хранить копию всего текста в документе отдельно от самого FlowDocument. Затем, когда вы применяете изменения к этому документу, вы можете обновлять форматирование по мере необходимости, без необходимости перечитывать документ. Обратите внимание, что текст не должен храниться в одном большом массиве, а должен быть разрезан на маленькие кусочки (возможно, около 1000 символов) и доступен через дерево, которое организует куски по индексу. Причина в том, что вставка символа в начале огромного массива очень дорога.

0 голосов
/ 13 марта 2010

Посмотрите здесь на CodeProject . Вот статья, которая может вас заинтересовать в отношении RichTextBox элемента управления, расширенного подклассами ... Посмотрите на этот элемент - Extended RichTextBox , который имеет больше функций

...