更新:我在this blog post 中详细阐述了这个主题。
我不认为有任何简单的方法可以做到这一点,但我将如何解决这个问题:
- 为列表中的项目定义视图模型。它应该包含一些属性来显示文本并定义应该突出显示文本的哪一部分(基本上是开始和结束索引)。
- 当用户在搜索框中输入文本时,查看视图模型并检查文本中的匹配项。如果找到匹配项,请适当设置索引。如果未找到匹配项,请将索引设置回 -1 或任何表示不匹配的值。
- 在您看来,将
TextBlocks 的Background 设置为索引。使用转换器将索引转换为两个索引之间的GradientBrush,即亮黄色(或其他)。
我认为您可以通过以下方式找出TextBlock 突出显示部分的尺寸:
- 通过
TextBlock.ContentStart 属性获取TextPointer。
- 使用
LogicalDirection.Forwards 调用TextPointer.GetPositionAtOffset(indexOfStart) 移动到选择的开头。
- 使用
LogicalDirection.Backwards 调用TextPointer.GetPositionAtOffset(indexOfStart) 移动到选择的末尾。
- 调用
TextPointer.GetCharacterRect获取突出显示内容的边界Rectangle。
说实话,我不确定最后一点是否有效。我必须自己尝试一下,我可能会为博客文章这样做。
编辑:刚刚有时间亲自尝试一下。它确实有效,尽管我上面的逻辑略有改变。下面是演示的代码。这是截图:
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);
}
}
}
}
我认为代码是不言自明的。显然,您需要将该概念扩展到您的特定场景。您可能更愿意利用TextBlock 的Background 属性与DrawingBrush 或GradientBrush 结合使用,而不是使用单独的Path。