Как обрабатывать/редактировать большой объем текста в WPF?

Что было бы хорошим подходом для отображения и редактирования большого количества неформатированного текста (как это делает блокнот) с помощью WPF? Загрузка большой строки в TextBox делает пользовательский интерфейс невосприимчивым. Общая производительность несопоставима с элементами управления TextBox предыдущих фреймворков пользовательского интерфейса Microsoft.

Какие варианты у меня есть, чтобы решить эту проблему. Я не хочу блокировать поток пользовательского интерфейса, пока текстовый элемент управления загружает текст. Также мне может понадобиться какая-то «виртуализация», потому что может быть не очень хорошей идеей загружать весь текст в элемент управления (я думаю, что 20 МБ текста создадут много глифов, даже если они не видны). Кажется, что у TextBox больше нет метода AppenText(), поэтому у меня даже нет способа контролировать асинхронную загрузку текста.

Разве это не общая проблема? Похоже, WPF ничего для этого не предоставляет из коробки. Почему это так?


person bitbonk    schedule 30.04.2009    source источник
comment
Я немного поиграл с ним. Проблема, кажется, как-то связана с вычислением области прокрутки. Если вы отключите полосу прокрутки, проблема как бы исчезнет - если вы не нажмете Ctrl + End (и тогда он должен вычислить дно или что-то в этом роде), шаблон содержимого для текстового поля hte представляет собой средство просмотра прокрутки. Возможно, проблема больше связана с оптимизацией средства просмотра прокрутки. Не ответ, а может подсказка?   -  person JMarsch    schedule 12.05.2009


Ответы (9)


AvalonEdit, текстовый редактор в SharpDevelop, был полностью написан с нуля в WPF и оптимизирован для работы с большими объемами текста. Он не поддерживает форматированный текст (хотя поддерживает подсветку синтаксиса и другие интересные функции, такие как свертывание). Я думаю, что это может идеально соответствовать вашим требованиям.

Вот статья о редакторе, написанная разработчиком:

http://www.codeproject.com/KB/edit/AvalonEdit.aspx

person Patrick Klug    schedule 04.08.2010
comment
Я тоже пришел к выводу, что написание собственного текстового элемента управления, вероятно, является лучшим решением. Хотя это немного грустно. - person bitbonk; 05.08.2010
comment
-1. Я использовал AvalonEdit с файлами размером 4 МБ или больше с ужасными результатами. Чрезвычайно глючит и крашит мое приложение, как сумасшедший бомбардировщик. - person code4life; 13.03.2012
comment
Только что создал новый проект VS WPF C#, добавил пакет NuGet AvalonEdit.Sample, изменил StartupUri, запустил и вуаля! Приложение AvalonEdit работает нормально. Текстовый файл размером 4 МБ с 8 тыс. строк открылся менее чем за секунду, тогда как TextBlock занял 22 секунды. Определенно может быть заменой TextBlock. - person David Oliván Ubieto; 07.02.2013
comment
Заменил TextBlock на элемент управления AvalonEdit в моем проекте (LOB-приложение с довольно сложным пользовательским интерфейсом), но, к сожалению, также тратит 20 секунд на загрузку того же файла, чем в AvalonEdit. Пример автономного приложения тратит ‹ 1 секунды. - person David Oliván Ubieto; 07.02.2013
comment
Заменил TextBlock на AvalonEdit, и все заработало. Мне нужно что-то придумать для обновления DocumentModel в фоновом потоке. - person Poul K. Sørensen; 29.03.2013

Я не уверен, поможет ли это, но пробовали ли вы использовать FlowDocumentPageViewer и FlowDocumentReader ?

Он также имеет очень хорошую поддержку аннотаций и идеально подходит для загрузки документов в текстовом формате.

person Vin    schedule 11.05.2009

Проблема в том, что TextBox является единственным элементом контейнера. Элементы управления списками, такие как ListBox, очень хорошо виртуализируются из-за повторного использования контейнеров. На самом деле нет ничего простого, что вы могли бы сделать, чтобы ускорить TextBox.

Но элемент управления TextBox имеет метод AppendText():

        TextBox tb = new TextBox();
        tb.AppendText("Hello");

Так что да, вы можете использовать это для динамического добавления текста, как вы упомянули.

person Samuel McAravey    schedule 11.05.2009
comment
Круто, я читал документы и унаследованные члены были спрятаны. Поскольку AppendText() исходит из TextBoxBase, я его не видел. - person bitbonk; 12.05.2009
comment
Это работает хорошо и быстро: я могу добавить 10 000 новых строк в TextBox примерно за секунду. Поскольку все виртуализировано, прокрутка происходит очень быстро. - person Contango; 04.11.2014

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

person Lukasz    schedule 30.04.2009
comment
Основная проблема здесь — производительность и удобство использования. Я не хочу блокировать поток пользовательского интерфейса, пока текстовый элемент управления загружает текст, также мне может понадобиться какая-то виртуализация, потому что может быть не очень хорошей идеей загружать весь текст в элемент управления (20 МБ текста создаст много глифов ). - person bitbonk; 30.04.2009
comment
В этом случае я бы выбрал сторонний контроль. Вы можете удалить дополнительные функции форматирования и сделать его простым, как Блокнот. Сторонний элемент управления должен иметь возможность лучше обрабатывать объемы текста, о которых вы говорите. Вы также можете загрузить текст в другой поток, а затем привязать его к элементу управления после его загрузки. - person Lukasz; 30.04.2009

Вы всегда можете смешивать и сочетать технологии: вы можете поместить текстовое поле WinForms в родительский объект WPF. Вы теряете такие вещи, как стиль, непрозрачность, анимация, преобразования и т. д., но если все, что имеет значение, — это редактирование текста, текстовое поле WinForms отлично с этим справляется.

person Joe White    schedule 07.05.2009
comment
Это печально, но, наверное, лучший вариант. - person bitbonk; 08.05.2009

Вы пробовали WPF RichTextBox? Вы определенно захотите прочитать информацию о FlowDocument, если пойдете по этому пути.

person Lurker Indeed    schedule 11.05.2009
comment
я удивлен, что этот базовый не обрабатывается из коробки. Совершенно не интуитивно понятно, как привязать текст к форматированному текстовому полю. - person BraveNewMath; 19.04.2013

Вы можете использовать FlowDocument, но это не работает из коробки для привязки к свойству Document FlowDocument в MVVM.

Другим решением является использование FlowDocumentScrollViewer и привязка к его свойству Document.

(или вы даже можете использовать FlowDocumentReader и привязать его свойство Document, аналогично FlowDocumentScrollViewer. Это даст вам другой пользовательский интерфейс.)

Вид:

 <FlowDocumentScrollViewer Document="{Binding FlowDocument, Mode=OneWay}" />

Модель представления:

   FlowDocument fd = new FlowDocument();
        Paragraph p = new Paragraph();
        Run r = new Run();
        r.Text = "large text";
        p.Inlines.Add(r);
        fd.Blocks.Add(p);
        FlowDocument = fd;

 private FlowDocument _FlowDocument;
    public FlowDocument FlowDocument
    {
      get{ return _FlowDocument; }
      set
      {
        _FlowDocument = value;
        NotifyOfPropertyChange(nameof(FlowDocument));
      }
    }

см. также дополнительные советы по повышению производительности: https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/optimizing-performance-text#flowdocument-textblock-and-label-controls

person juFo    schedule 03.10.2017

Еще один вариант — использовать Scintilla.NET. У него лучшая производительность для больших объемов текстов, которые я когда-либо видел. Загрузка больших файлов практически мгновенная. Несмотря на то, что это элемент управления WinForms, вы можете встроить его в окно WPF с помощью контейнера WindowsFormsHost. Есть подсветка синтаксиса и некоторые другие функции, которых должно быть более чем достаточно для отображения неформатированного текста. Из недостатков — поскольку это элемент управления WinForms, он перекрывает другие элементы пользовательского интерфейса WPF. Также могут возникнуть проблемы с изменением размера элемента управления. К сожалению, я не вижу лучшего варианта, чем использование элемента управления, отличного от WPF, вместо стандартных TextBox и RichTextBox.

person username    schedule 04.11.2019

Как насчет того, чтобы попробовать что-то вроде этого:

Сохраняйте всю строку в памяти, но отображайте только ее «фрагмент» в текстовом поле. Размер этой нарезанной строки будет вычисляться динамически в зависимости от размера текстового поля, размера шрифта и т. д.

Конечно, это включает в себя много нетривиального кода для правильного отображения, синхронизации и т. д., но, похоже, это правильный путь.

person arconaut    schedule 07.05.2009