Highlight found text in ListBox for Silverlight and WP7

You probably saw an implementation of search where all matches of the entered query were highlighted in the text or list, or table. Here are 2 screenshots which illustrate the described functionality:

It is very easy to implement in Javascript, just 4 lines:

var html = element.html();
html = html.replace(new RegExp("<span class=\"highlighted\">(.*?)<\/span>", "i"), "$1"); // clear the previous highlight
html = html.replace(new RegExp("(" + query + ")", "i"), "<span class=\"highlighted\">$1</span>"); // highlight the current search query
element.html(html);

But it is slightly more difficult in Silverlight. However the approach is the same:
1. Get the text value.
2. Replace some places in the text by a span with some user-defined style.
3. Parse the result text and display it.

I have created a new project by using the Windows Phone Databound Application template in Visual Studio, so that I don’t need to create base mark-up and add default data, Visual Studio creates everything by itself.

At first, we need to write methods which replace values of ListBox by formatted values. The corresponding javascript code is `html.replace(new Regexp(…))`. The C# code looks so:

public void Search()
{
    this.ClearHighlights();

    if(string.IsNullOrEmpty(SearchQuery))
    {
        return;
    }

    this.AddHighlights();
}

private void ClearHighlights()
{
    var highlightRegex = new Regex("<Run Foreground='Yellow'>(.*?)</Run>");
    foreach (var item in this.Items)
    {
        item.LineOne = highlightRegex.Replace(item.LineOne, "$1");
        item.LineTwo = highlightRegex.Replace(item.LineTwo, "$1");
    }
}

private void AddHighlights()
{
    var searchRegex = new Regex(string.Format("({0})", this.SearchQuery), RegexOptions.IgnoreCase);
    foreach (var item in this.Items)
    {
        item.LineOne = searchRegex.Replace(item.LineOne, "<Run Foreground='Yellow'>$1</Run>");
        item.LineTwo = searchRegex.Replace(item.LineTwo, "<Run Foreground='Yellow'>$1</Run>");
    }
}

The `LineOne` and `LineTwo` properties contain some strings which are displayed in each item of the ListBox.

Finally, we need to write a binding which correctly displays a text with the `Run` tags. The corresponding javascript code is `elem.html(html)`. I used attached property for this task:

public static class TextBlockProperties
{
    public static string GetStyledText(DependencyObject obj)
    {
        return (string)obj.GetValue(StyledTextProperty);
    }

    public static void SetStyledText(DependencyObject obj, string value)
    {
        obj.SetValue(StyledTextProperty, value);
    }

    public static readonly DependencyProperty StyledTextProperty =
        DependencyProperty.RegisterAttached("StyledText", typeof(string), typeof(TextBlock), new PropertyMetadata(null, StyledText_Changed));


    private static void StyledText_Changed(DependencyObject d, DependencyPropertyChangedEventArgs args)
    {
        var tb = (TextBlock) d;
        var text = (string) args.NewValue;

        if(string.IsNullOrEmpty(text) || !Regex.IsMatch(text, "<Run.*?>.*?</Run>"))
        {
            tb.Text = text;
            return;
        }

        var formattedTextBlockXaml = "<TextBlock xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" + text + "</TextBlock>";
        var formattedTextBlock = (TextBlock) XamlReader.Load(formattedTextBlockXaml);

        // detach parsed inlines from the view tree
        var inlines = formattedTextBlock.Inlines.ToList();
        formattedTextBlock.Inlines.Clear();

        // add inlines to the specified text block
        tb.Inlines.Clear();
        foreach (var inline in inlines)
        {
            tb.Inlines.Add(inline);
        }
    }
}

So now all that you need is to use the StyledText property instead of Text:

<TextBlock ext:TextBlockProperties.StyledText="{Binding LineOne}" />

In my example I used the yellow color for highlighting, but you can change any property of the `Run` class, like FontWeight (Bold), FontStyle (Italic) and others, the list of properties you can find here: Run Class.

The sample application which I used in order to make the 2 screenshots above you can download here: Wp7ListSearchSample.zip

Advertisements

One Response to Highlight found text in ListBox for Silverlight and WP7

  1. Washington says:

    100000% perfect.
    Tnks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: