更新:我在这篇博客文章中对这个主题进行了详细阐述。
我认为没有简单的方法来解决这个问题,但是以下是我处理这个问题的方式:
- 为列表中的项目定义一个视图模型。它应该包括公开文本并定义应突出显示文本的哪个部分(基本上是起始和结束索引)的属性。
- 当用户在搜索框中输入文本时,请查看视图模型并检查文本是否匹配。如果找到匹配项,请适当设置索引。如果找不到匹配项,请将索引设置回-1或任何表示无匹配项的值。
- 在视图中,将
TextBlock
的Background
设置为索引。使用转换器将索引转换为GradientBrush
,在两个索引之间变成明亮的黄色(或其他颜色)。
以下是我认为可以确定TextBlock
的突出显示部分的尺寸的方法:
- 通过
TextBlock.ContentStart
属性获取TextPointer
。
- 使用
LogicalDirection.Forwards
调用TextPointer.GetPositionAtOffset(indexOfStart)
移动到选择的开头。
- 使用
LogicalDirection.Backwards
调用TextPointer.GetPositionAtOffset(indexOfStart)
移动到选择的结尾。
- 调用
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);
}
}
}
}
我认为这段代码相当容易理解。显然,你需要根据你的具体情况扩展这个概念。你可能更喜欢利用 TextBlock
的 Background
属性与 DrawingBrush
或 GradientBrush
相结合,而不是使用单独的 Path
。