У меня была похожая проблема - попытка реализовать текстовый поиск по множеству докладчиков, которые в основном представляют отчет. Первоначально отчет был записан в строку, и мы использовали встроенный в Ctrl-F FlowDocumentViewer - он не очень хорош и имеет некоторые странные опции, но его было достаточно.
Если вы просто хотите что-то подобное, вы можете сделать следующее:
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph FontFamily="Lucida Console" FontSize="12">
<Run Text="{Binding Content, Mode=OneWay}"/>
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
Мы решили пойти на переписывание, так как отчет синхронизирован с остальной частью программы, и в основном каждое изменение меняет его, необходимость повторного создания всего отчета каждый раз означает, что это довольно медленно. Мы хотели улучшить это, перейдя к модели «обнови нужные биты», но нам нужно было иметь модель представления (а не просто строку), чтобы иметь возможность делать это разумным способом! Мы хотели сохранить функциональность поиска, прежде чем поменять отчет, и сделать его лучше, выделив «текущую» позицию поиска одним цветом, а другие результаты поиска - другим.
Вот упрощенная версия моего решения; класс, производный от TextBlock, который добавляет свойство зависимости типа HighlightingInformation. Я не включил пространство имен и использование, поскольку они чувствительны.
public class HighlightingTextBlock : TextBlock
{
public static readonly DependencyProperty HighlightingProperty =
DependencyProperty.Register("Highlighting", typeof (HighlightingInformation), typeof (HighlightingTextBlock));
public HighlightingInformation Highlighting
{
get { return (HighlightingInformation)GetValue(HighlightingProperty); }
set { SetValue(HighlightingProperty, value); }
}
public HighlightingTextBlock()
{
AddValueChangedCallBackTo(HighlightingProperty, UpdateText);
}
private void AddValueChangedCallBackTo(DependencyProperty property, Action updateAction)
{
var descriptor = DescriptorFor(property);
descriptor.AddValueChanged(this, (src, args) => updateAction());
}
private DependencyPropertyDescriptor DescriptorFor(DependencyProperty property)
{
return DependencyPropertyDescriptor.FromProperty(property, GetType());
}
private void UpdateText()
{
var highlighting = Highlighting;
if (highlighting == null)
return;
highlighting.SetUpdateMethod(UpdateText);
var runs = highlighting.Runs;
Inlines.Clear();
Inlines.AddRange(runs);
}
}
Тип, к которому может быть привязан этот класс, использует метод update, когда его текст и список бликов изменяются для обновления списка прогонов. Сами блики выглядят примерно так:
public class Highlight
{
private readonly int _length;
private readonly Brush _colour;
public int Start { get; private set; }
public Highlight(int start, int length,Brush colour)
{
Start = start;
_length = length;
_colour = colour;
}
private string TextFrom(string currentText)
{
return currentText.Substring(Start, _length);
}
public Run RunFrom(string currentText)
{
return new Run(TextFrom(currentText)){Background = _colour};
}
}
Создание правильной коллекции бликов - это отдельная проблема, которую я в основном решил, рассматривая коллекцию презентаторов как дерево, которое вы рекурсивно ищите для контента - это конечные узлы, у которых есть контент, а у других узлов просто есть дочерние элементы. Если вы начнете поиск по глубине, вы получите ожидаемый порядок. Затем вы можете написать обертку вокруг списка результатов, чтобы отслеживать положение. Я не собираюсь публиковать весь код для этого - мой ответ здесь, чтобы документировать, как вы можете заставить wpf делать разноцветную подсветку в стиле MVP.
Я не использовал INotifyPropertyChanged или CollectionChanged здесь, так как нам не нужно, чтобы изменения были многоадресными (например, один докладчик имеет несколько представлений). Сначала я попытался сделать это, добавив уведомление об изменении события для текста и одно для списка (на который вы также должны вручную подписаться на событие INotifyCollectionChanged). Однако у меня были опасения по поводу утечек памяти при подписке на события и того факта, что обновления для текста и основных моментов не происходили одновременно, что делало его проблематичным.
Единственным недостатком этого подхода является то, что люди не должны привязываться к свойству Text этого элемента управления. В реальной версии я добавил несколько проверок и исключений, чтобы люди не делали этого, но для ясности исключили это из примера!