WPF列表框突出显示ListBoxItem元素的一部分

Dan*_*rik 3 .net wpf xaml listbox highlighting

我有一个TextBox和ListBox.用户可以从TextBox中搜索ListBox元素.

ListBox绑定到CollectionViewSource.

CollectionViewSource具有Filter事件处理程序,可根据用户输入TextBox的文本过滤元素.

我的要求是突出显示用户在ListBoxItem元素的TextBlock中输入的文本.

我正在考虑将TextBlock分成几个Runs对象,并修改需要突出显示的Run对象的Background属性.

我认为不可能使用DataTemplates.

有没有简单的方法来实现这一目标?

谢谢!

Ken*_*art 9

更新:我在这篇博文中详细阐述了这个主题.

我认为没有任何简单的方法可以做到这一点,但这是我将如何解决这个问题:

  1. 为列表中的项定义视图模型.它应包括公开文本的属性,并定义应突出显示文本的哪一部分(基本上是开始和结束索引).
  2. 当用户在搜索框中输入文本时,请查看视图模型并检查文本中的匹配项.如果找到匹配项,请相应地设置索引.如果未找到匹配项,请将索引设置回-1或任何表示不匹配的索引.
  3. 在您看来,设置Background了的TextBlocks到索引.使用转换器将索引转换为GradientBrush两个索引之间的亮黄色(或其他).

以下是我认为您可以找出以下突出显示部分的尺寸TextBlock:

  1. 获得TextPointer通过的TextBlock.ContentStart性质.
  2. 通过调用TextPointer.GetPositionAtOffset(indexOfStart)使用移动到选择的开头LogicalDirection.Forwards.
  3. 通过调用TextPointer.GetPositionAtOffset(indexOfStart)使用移动到选择的末尾LogicalDirection.Backwards.
  4. 调用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>
Run Code Online (Sandbox Code Playgroud)

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为代码是相当不言自明的.显然,您需要将概念扩展到您的特定场景.您可能更愿意利用与a结合使用的Background属性,或者不使用单独的属性.TextBlockDrawingBrushGradientBrushPath