How to highlight matching sub-strings inside a ListBox?

后端 未结 1 900
傲寒
傲寒 2021-01-06 02:42

I have one TextBox and one listbox for searching a collection of data. While searching a text inside a Listbox if that matching string is found anywhere in the list it shoul

相关标签:
1条回答
  • 2021-01-06 03:39

    I've created a HighlightTextBehavior that you can attach to a TextBlock within your list item templates (you'll need to add a reference to System.Windows.Interactivity to your project). You bind the behavior to a property containing the text you want to highlight, and it does the rest.

    At the moment, it only highlights the first instance of the string. It also assumes that there is no other formatting applied to the text.

    using System.Linq;
    using System.Text;
    using System.Windows.Interactivity;
    using System.Windows.Controls;
    using System.Windows;
    using System.Windows.Documents;
    using System.Windows.Media;
    
    namespace StringHighlight
    {
        public class HighlightTextBehavior : Behavior<TextBlock>
        {
            public string HighlightedText
            {
                get { return (string)GetValue(HighlightedTextProperty); }
                set { SetValue(HighlightedTextProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for HighlightedText.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty HighlightedTextProperty =
                DependencyProperty.Register("HighlightedText", typeof(string), typeof(HighlightTextBehavior), new UIPropertyMetadata(string.Empty, HandlePropertyChanged));
    
            private static void HandlePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                (sender as HighlightTextBehavior).HandlePropertyChanged();
            }
    
            private void HandlePropertyChanged()
            {
                if (AssociatedObject == null)
                {
                    return;
                }
    
                var allText = GetCompleteText();
    
                AssociatedObject.Inlines.Clear();
    
                var indexOfHighlightString = allText.IndexOf(HighlightedText);
    
                if (indexOfHighlightString < 0)
                {
                    AssociatedObject.Inlines.Add(allText);
                }
                else
                {
                    AssociatedObject.Inlines.Add(allText.Substring(0, indexOfHighlightString));
                    AssociatedObject.Inlines.Add(new Run() { 
                        Text = allText.Substring(indexOfHighlightString, HighlightedText.Length), 
                        Foreground = Brushes.Green,
                        FontWeight = FontWeights.Bold });
                    AssociatedObject.Inlines.Add(allText.Substring(indexOfHighlightString + HighlightedText.Length));
                }
            }
    
            private string GetCompleteText()
            {
                var allText = AssociatedObject.Inlines.OfType<Run>().Aggregate(new StringBuilder(), (sb, run) => sb.Append(run.Text), sb => sb.ToString());
                return allText;
            }
        }
    }
    

    Here's an example of how you use it:

        <Window x:Class="StringHighlight.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            xmlns:b="clr-namespace:StringHighlight"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.Resources>
                <x:Array x:Key="MyStrings" Type="{x:Type sys:String}">
                    <sys:String>This is my first string</sys:String>
                    <sys:String>Another string</sys:String>
                    <sys:String>A third string, equally imaginative</sys:String>
                </x:Array>
            </Grid.Resources>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBox x:Name="SearchText"/>
    
            <ListBox Grid.Row="1" ItemsSource="{StaticResource MyStrings}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Grid.Row="1" Text="{Binding}">
                            <i:Interaction.Behaviors>
                                <b:HighlightTextBehavior HighlightedText="{Binding ElementName=SearchText, Path=Text}"/>
                            </i:Interaction.Behaviors>
                        </TextBlock>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Window>
    
    0 讨论(0)
提交回复
热议问题