How to display search results in a WPF items control with highlighted query terms

后端 未结 3 607
天涯浪人
天涯浪人 2020-12-03 16:06

I\'d like to display search results within a WPF ItemsControl with the query terms highlighted.

The search engine I use, Lucene.Net with the Highlighter plugin, retu

相关标签:
3条回答
  • 2020-12-03 16:12

    I found a way to apply highlighting to search results using a custom IValueConverter. The converter takes a text snippet, formats it into valid XAML markup, and uses a XamlReader to instantiate the markup into framework objects.

    The full explanation is rather long, so I've posted it to my blog: Highlighting Query Terms in a WPF TextBlock

    0 讨论(0)
  • 2020-12-03 16:16

    I took dthrasers answer and took out the need for an XML parser. He does a great job explaining each of the pieces in his blog, However this didn't require me to add any extra libraries, here's how I did it.

    Step one, make a converter class:

    class StringToXamlConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string input = value as string;
            if (input != null)
            {
                var textBlock = new TextBlock();
                textBlock.TextWrapping = TextWrapping.Wrap;
                string escapedXml = SecurityElement.Escape(input);
                
                while (escapedXml.IndexOf("|~S~|") != -1) {
                    //up to |~S~| is normal
                    textBlock.Inlines.Add(new Run(escapedXml.Substring(0, escapedXml.IndexOf("|~S~|"))));
                    //between |~S~| and |~E~| is highlighted
                    textBlock.Inlines.Add(new Run(escapedXml.Substring(escapedXml.IndexOf("|~S~|") + 5,
                                              escapedXml.IndexOf("|~E~|") - (escapedXml.IndexOf("|~S~|") + 5))) 
                                              { FontWeight = FontWeights.Bold, Background= Brushes.Yellow });
                    //the rest of the string (after the |~E~|)
                    escapedXml = escapedXml.Substring(escapedXml.IndexOf("|~E~|") + 5);
                }
    
                if (escapedXml.Length > 0)
                {
                    textBlock.Inlines.Add(new Run(escapedXml));                      
                }
                return textBlock;
            }
    
            return null;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException("This converter cannot be used in two-way binding.");
        }
    }
    

    Step two: Instead of a TextBlock use a ContentBlock. Pass in the string (you would of used for your textBlock) to the content block, like so:

    <ContentControl
                   Margin="7,0,0,0"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Center"
                   Content="{Binding Description, Converter={StaticResource CONVERTERS_StringToXaml}, Mode=OneTime}">
    </ContentControl>
    

    Step three: Make sure the test you pass in is tokenized with |~S~| and |~E~|. And let the highlighting begin!

    Notes:
    You can change the style in the run to determine what and how your text is highlighted
    Make sure you add your Converter class to your namespace and resources. This might also require a rebuild to get working.

    0 讨论(0)
  • 2020-12-03 16:25

    A TextBlock can contain multiple Runs in its Inlines collection. You can build it in code or in XAML:

    <TextBlock>
        <Run>... these </Run>
        <Run FontWeight="Bold">results</Run>
        <Run> were found...</Run>
    </TextBlock>
    
    0 讨论(0)
提交回复
热议问题