Страницы

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

понедельник, 11 февраля 2019 г.

TextBlock с подсветкой текста

Столкнулся с необходимостью выделения фрагмента текста в TextBlock, а именно определённых ключевых слов по которым были отфильтрованы элементы ListBox , этот текстовый блок собственно и содержащие
XAML, мой ваиант


Вариант XAML, рекомендованный VladD, не создаёт коллекцию HighlightRulesCollection (хотя казалось бы даже отрабатывает конвертер)
Используется компонент написанный нашим соотечественником с открытым исходным Компонент
Описание компонента
Закомментированный код это старый TexBlock без выделения
Новый компонент HighlightTextBlock прекрасно выделяет текст если использовать статический ресурс, как в примере, но когда я пытаюсь его привязать к текущему тексту он не может найти это поле :( , я новенький в WPF помогите разобраться с
HightlightedText="{Binding Path=title, Converter={StaticResource getFilter}}"
Изначально вопрос звучал как верно привязать это свойство к title ? Мне дали совет по реструктуризации XAML, через ресурсы , но это не работает т.к. не создаётся HighlightRulesCollection и выделение не работает.
В ходе обсуждения было высказано предположение что следует несколько модифицировать сам компонент и поместить коллекцию HighlighRule (также) в визуальное дерево. Тогда будет автоматически наследоваться DataContext и по идее будет работать привязка через ElementName.
Подскажите как это можно реализовать? или может кто то внесёт правки в исходный код компонента ?
Альтернативный вариант , подскажите, как реализовать такого рода функционал другими методами ?
структура DataContext
public ObservableCollection Procedures { set; get; } public CollectionViewSource ProceduresView { set; get; } = new CollectionViewSource();
....
Procedures = new ObservableCollection();
ProceduresView.Filter += Procedures_Filter; ProceduresView.Source = Procedures;
....
public class Procedure : ObservableObject { .... public String title { get; set; } .... } ....
// Просто фильтрация
void Procedures_Filter(object sender, FilterEventArgs e) { Procedure procedure = (Procedure) e.Item; Boolean flag = false; if (!string.IsNullOrEmpty(filter)) { Setting.Filter sfilter = new Setting.Filter(); sfilter.type = "искать везде"; sfilter.text = filter; ObservableCollection arr = new ObservableCollection(); arr.Add(sfilter); if (Utils.AssignedProcedureFromFilter(procedure, arr)) flag = true; } else flag = true; e.Accepted = flag; }
Видео с описанием проблемы
Упрощённый проект эмитирующий мой функционал


Ответ

Нашёл работающее решение своей задачи
public class SearchHightlightTextBlock : TextBlock { public SearchHightlightTextBlock() : base() { }
public String SearchText { get { return (String)GetValue(SearchTextProperty); } set { SetValue(SearchTextProperty, value); } }
private static void OnDataChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { TextBlock tb = (TextBlock)source;
if (tb.Text.Length == 0) return;
string textUpper = tb.Text.ToUpper(); String toFind = ((String)e.NewValue).ToUpper(); int firstIndex = textUpper.IndexOf(toFind); String firstStr = ""; String foundStr = ""; if (firstIndex != -1) { firstStr = tb.Text.Substring(0, firstIndex); foundStr = tb.Text.Substring(firstIndex, toFind.Length); } String endStr = tb.Text.Substring(firstIndex + toFind.Length, tb.Text.Length - (firstIndex + toFind.Length));
tb.Inlines.Clear(); tb.FontSize = 16; var run = new Run(); run.Text = firstStr; tb.Inlines.Add(run); run = new Run(); run.Background = Brushes.Yellow; run.Text = foundStr; tb.Inlines.Add(run); run = new Run(); run.Text = endStr;
tb.Inlines.Add(run); }
public static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register("SearchText", typeof(String), typeof(SearchHightlightTextBlock), new FrameworkPropertyMetadata(null, OnDataChanged)); }
Использовать вот так

Не совсем элегантное решение , но работает привязка и все дела :)

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

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