ОБНОВЛЕНИЕ: я подробно остановился на этой теме в этом сообщении в блоге .
Не думаю, что есть простой способ сделать это, но вот как я бы решил эту проблему:
- Определить модель представления для элементов в списке. Он должен включать свойства, позволяющие отобразить текст и определить, какая часть текста должна быть выделена (в основном, начальный и конечный индексы).
- Когда пользователь вводит текст в поле поиска, просматривайте модели просмотра и проверяйте совпадения в тексте. Если совпадение найдено, установите индексы соответствующим образом. Если совпадение не найдено, установите индексы обратно на -1 или что-то еще, что не соответствует.
- По вашему мнению, установите
Background
из TextBlock
s на индексы. Используйте конвертер для преобразования индексов в ярко-желтый (или любой другой) GradientBrush
между двумя индексами.
Вот как Я думаю Вы можете вычислить размеры выделенных частей TextBlock
:
- Получите
TextPointer
через свойство TextBlock.ContentStart
.
- Перейдите к началу выбора, набрав
TextPointer.GetPositionAtOffset(indexOfStart)
, используя LogicalDirection.Forwards
.
- Переместитесь в конец выделения, набрав
TextPointer.GetPositionAtOffset(indexOfStart)
, используя LogicalDirection.Backwards
.
- Позвоните
TextPointer.GetCharacterRect
, чтобы получить ограничение Rectangle
выделенного содержимого.
Если честно, я не уверен, что последний бит сработает. Я должен попробовать это для себя, и я могу сделать это для сообщения в блоге.
РЕДАКТИРОВАТЬ : Просто было время, чтобы попробовать это для себя. Это определенно работает, хотя с небольшими изменениями в моей логике выше. Ниже приведен код, который демонстрирует. Вот скриншот:
Скриншот 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);
}
}
}
}
Я думаю, что код довольно понятен. Очевидно, вам нужно будет расширить концепцию до вашего конкретного сценария. Вы можете предпочесть использовать свойство Background
TextBlock
в сочетании с DrawingBrush
или GradientBrush
вместо использования отдельного Path
.