UPDATE: I have elaborated on this question in this blog post .
I don't think there is an easy way to do this, but here is how I could solve this problem:
- Define a presentation model for the items in the list. It should include properties for expanding the text and determining how much of the text should be highlighted (start and end indexes, mainly).
- When the user enters text in the search field, browse the view models and check for matches in the text. If a match is found, set the indexes accordingly. If no match is found, set the indices to -1 or something else doesn't match.
- In your opinion, set
Background from TextBlock to indexes. Use the converter to convert indexes to GradientBrush , bright yellow (or any other) between two indexes.
Here, as I think, you can find out the sizes of the selected parts of the TextBlock :
- Get a
TextPointer using the TextBlock.ContentStart property. - Scroll to the top of the selection by calling
TextPointer.GetPositionAtOffset(indexOfStart) using LogicalDirection.Forwards . - Move to the end of the selection by calling
TextPointer.GetPositionAtOffset(indexOfStart) using LogicalDirection.Backwards . - Call
TextPointer.GetCharacterRect to get the Rectangle constraint of the selected content.
Honestly, I'm not sure if the last bit is working. I have to try this for myself, and I can do it for a blog post.
EDIT : I had time to try this for myself. This definitely works, although with a few changes in my logic above. Below is the code that demonstrates. Here is a screenshot:
Screenshot http://img219.imageshack.us/img219/2969/searchx.png
Window1.xaml:
<Window x:Class="TextSearch.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1"> <StackPanel> <TextBox x:Name="_searchTextBox"/> <Grid> <Path Fill="Yellow" Stroke="Black" StrokeThickness="0"> <Path.Data> <RectangleGeometry x:Name="_rectangleGeometry"/> </Path.Data> </Path> <TextBlock x:Name="_textBlock">Some sample text that you can search through by typing in the above TextBox.</TextBlock> </Grid> </StackPanel> </Window>
Window1.xaml.cs:
using System.Windows; using System.Windows.Controls; using System.Windows.Documents; namespace TextSearch { public partial class Window1 : Window { public Window1() { InitializeComponent(); _searchTextBox.TextChanged += _searchTextBox_TextChanged; } void _searchTextBox_TextChanged(object sender, TextChangedEventArgs e) { var searchText = _searchTextBox.Text; var index = _textBlock.Text.IndexOf(searchText); if (index == -1) { _rectangleGeometry.Rect = Rect.Empty; } else { var textPointer = _textBlock.ContentStart; textPointer = textPointer.GetPositionAtOffset(index + 1, LogicalDirection.Forward); var leftRectangle = textPointer.GetCharacterRect(LogicalDirection.Forward); textPointer = textPointer.GetPositionAtOffset(searchText.Length, LogicalDirection.Backward); var rightRectangle = textPointer.GetCharacterRect(LogicalDirection.Forward); _rectangleGeometry.Rect = new Rect(leftRectangle.TopLeft, rightRectangle.BottomRight); } } } }
I think the code is pretty clear. Obviously, you will need to extend the concept to your specific scenario. You can use the Background TextBlock property in combination with a DrawingBrush or GradientBrush instead of having a separate Path .
source share