5

我的目标是创建一个具有新依赖属性 SearchText 的自定义 TextBlock 控件。该属性将包含一个正则表达式。在 TextBlock 的文本中出现的所有此正则表达式都将使用自定义样式(另一个 DP)突出显示。

我当前的实现涉及清除 TextBlock 的 InlineCollection 中的所有 Inline 对象。然后,我用运行未突出显示的文本填充 TextBlock,并运行应用样式的突出显示文本(此方法不支持直接将内联添加到 TextBlock,而是必须使用 TextBlock.TextProperty)。

效果很好,但有时我在尝试清除内联时遇到一个奇怪的异常: InvalidOperationException:“此时无法修改此节点的逻辑子节点,因为正在进行树遍历。”

这个问题似乎与这个有关。我正在修改 TextChanged 函数中的内联,但我使用了一个标志来避免无限递归编辑。

关于如何构建此自定义控件的任何想法?有一个更好的方法吗?我该如何解决这个异常?

谢谢!

4

3 回答 3

6

在我的实现中,我通过添加另一个名为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;
    }
}
于 2014-04-17T12:49:36.883 回答
3

仍然不确定是否有更好的方法可以完全做到这一点,但我似乎找到了解决方法。

我正在更新由 TextProperty 和 SearchTextProperty 的更改通知触发的函数中的内联/运行。

现在,我正在使用 DispatcherPriority.Normal 从更改通知中的 Dispatcher.BeginInvoke() 调用中触发突出显示/更新代码。

于 2010-10-06T15:25:00.587 回答
2

如果有人想要一个如何做到这一点的例子,我发现了这个

于 2012-01-31T09:54:15.417 回答