user1202434
user1202434

Reputation: 2273

ItemsSource highlight when filtering wpf?

I have an ItemsSource bound up to my data. I have a TextBox that as the user starts typing it in, I filter the items based on the following Filter predicate on the textBoxText changed event:

ICollectionView listView = CollectionViewSource.GetDefaultView(myControl.ItemsSource);

listView.Filter = ((x) => 
{           
    MyData data = x as MyData;
    return data.Name.Contains(searchString, System.StringComparison.InvariantCultureIgnoreCase);
});

This works fine and filters the list. However I also want the items to highlight in yellow the entered search criteria as they type. How can I do that in wpf? Kind of like:

If i searched for "est" and the item is Forest The Forest item highlights est in yellow or any other color in the ListBox? Thanks for any suggestions.

Upvotes: 1

Views: 801

Answers (1)

TKharaishvili
TKharaishvili

Reputation: 2099

I achieved this by creating a custom control - HighlightableTextBlock that inherits from TextBlock and adds the following dependency property:

    public string HighlightSource
    {
        get { return (string)GetValue(HighlightSourceProperty); }
        set { SetValue(HighlightSourceProperty, value); }
    }

    public static readonly DependencyProperty HighlightSourceProperty =
        DependencyProperty.Register("HighlightSource", typeof(string), typeof(HighlightableTextBlock), new PropertyMetadata("", OnChange));

Performing the actual highlighting in the OnChange event handler:

    static void OnChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBlock = d as HighlightableTextBlock;
        var text = textBlock.Text;
        var source = textBlock.HighlightSource;

        if (!string.IsNullOrWhiteSpace(source) && !string.IsNullOrWhiteSpace(text))
        {
            var index = text.IndexOf(source);
            if (index >= 0)
            {
                var start = text.Substring(0, index);
                var match = text.Substring(index, source.Length);
                var end = text.Substring(index + source.Length);

                textBlock.Inlines.Clear();
                textBlock.Inlines.Add(new Run(start));
                textBlock.Inlines.Add(new Run(match) { Foreground = Brushes.Red });
                textBlock.Inlines.Add(new Run(end));
            }
        }
    }

And the markup side of things looks like this:

<controls:HighlightableTextBlock Text="{Binding SomeText}"
                                 HighlightSource="{Binding ElementName=SearchTextBox, Path=Text}">
</controls:HighlightableTextBlock>

Seems to be working for me. I've hardcoded the color of the matched substring in this example, but you can add a separate property if you want to pass that from the markup as well.

Hope this helps...

Upvotes: 1

Related Questions