Выделите Поиск TextBlock - PullRequest
       31

Выделите Поиск TextBlock

4 голосов
/ 06 октября 2010

Моя цель - создать пользовательский элемент управления TextBlock с новым свойством зависимости SearchText.Это свойство будет содержать регулярное выражение.Все вхождения этого регулярного выражения в тексте TextBlock будут выделены с помощью пользовательского стиля (еще один DP).

Моя текущая реализация включает в себя очистку всех объектов Inline в InlineCollection TextBlock.Затем я заполняю TextBlock прогонами для невыделенного текста и прогонами для выделенного текста с примененным стилем (этот метод не поддерживает добавление строк непосредственно к TextBlock, вместо этого должен использоваться TextBlock.TextProperty).

Прекрасно работает, но иногда я получаю странное исключение при попытке очистить Inlines: InvalidOperationException: «В настоящее время невозможно изменить логические дочерние элементы для этого узла, так как выполняется обход дерева».

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

Есть мысли о том, как создать этот пользовательский элемент управления?Есть лучший способ сделать это?Как мне обойти это исключение?

Спасибо!

Ответы [ 3 ]

5 голосов
/ 17 апреля 2014

В моей реализации я решил эту проблему, просто добавив другое свойство зависимостей под названием OriginalText. Когда он был изменен, я обновил свойство Text и обновил подсветку. Вот код:

  public class HighlightTextBlock : TextBlock
{
    public string HighlightedText
    {
        get { return (string)GetValue(HighlightedTextProperty); }
        set { SetValue(HighlightedTextProperty, value); }
    }

    public static readonly DependencyProperty HighlightedTextProperty =
        DependencyProperty.Register("HighlightedText", typeof(string), typeof(HighlightTextBlock), new UIPropertyMetadata(string.Empty, UpdateHighlightEffect));

    public static readonly DependencyProperty OriginalTextProperty = DependencyProperty.Register(
        "OriginalText", typeof(string), typeof(HighlightTextBlock), new PropertyMetadata(default(string), OnOriginalTextChanged));

    private static void OnOriginalTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var block = ((HighlightTextBlock)obj);
        block.Text = block.OriginalText;
        block.UpdateHighlightEffect();
    }

    public string OriginalText
    {
        get { return (string)GetValue(OriginalTextProperty); }
        set { SetValue(OriginalTextProperty, value); }
    }

    private static void UpdateHighlightEffect(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        if (!(string.IsNullOrEmpty(e.NewValue as string) && string.IsNullOrEmpty(e.OldValue as string)))
            ((HighlightTextBlock)sender).UpdateHighlightEffect();
    }

    private void UpdateHighlightEffect()
    {
        if (string.IsNullOrEmpty(HighlightedText)) return;

        var allText = GetCompleteText();

        Inlines.Clear();

        var indexOfHighlightString = allText.IndexOf(HighlightedText, StringComparison.InvariantCultureIgnoreCase);

        if (indexOfHighlightString < 0)
        {
            Inlines.Add(allText);
        }
        else
        {
            Inlines.Add(allText.Substring(0, indexOfHighlightString));
            Inlines.Add(new Run()
                            {
                                Text = allText.Substring(indexOfHighlightString, HighlightedText.Length),
                                Background = Consts.SearchHighlightColor,
                            });
            Inlines.Add(allText.Substring(indexOfHighlightString + HighlightedText.Length));
        }

    }

    private string GetCompleteText()
    {
        var allText = Inlines.OfType<Run>().Aggregate(new StringBuilder(), (sb, run) => sb.Append(run.Text), sb => sb.ToString());
        return allText;
    }
}
2 голосов
/ 06 октября 2010

Все еще не уверен, есть ли лучший способ сделать это вообще, но я, кажется, нашел решение вокруг.

Я обновлял inline / запуски в функции, которая была запущена уведомлением об изменении для TextProperty и SearchTextProperty.

Теперь я запускаю код выделения / обновления из вызова Dispatcher.BeginInvoke () в уведомлении об изменении с помощью DispatcherPriority.Normal.

1 голос
/ 31 января 2012

На случай, если кому-нибудь понадобится пример того, как это сделать, я нашел this

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...