【问题标题】:Highlight Search TextBlock突出显示搜索文本块
【发布时间】:2014-04-17 20:49:36
【问题描述】:

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

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

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

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

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

谢谢!

【问题讨论】:

    标签: wpf custom-controls textblock invalidoperationexception inlines


    【解决方案1】:

    在我的实现中,我通过添加另一个名为 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】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 建议提供链接中的内容摘要,以防它被破坏。
      • 链接已损坏:/
      猜你喜欢
      • 2012-01-03
      • 1970-01-01
      • 2017-12-11
      • 2023-04-08
      • 1970-01-01
      • 2012-06-25
      • 2018-06-01
      • 2016-07-31
      相关资源
      最近更新 更多