WPF ListBox如何高亮显示ListBoxItem元素的一部分

3
我有一个文本框和列表框。用户可以通过文本框搜索列表框元素。
列表框绑定到CollectionViewSource。
CollectionViewSource具有过滤器事件处理程序,该处理程序根据用户在文本框中输入的文本来过滤元素。
我的要求是在ListBoxItem元素的TextBlock中突出显示用户输入的文本。
我考虑将TextBlock分成几个Runs对象,并修改需要突出显示的Run对象的Background属性。
我认为使用DataTemplates无法实现此操作。
有没有简单的方法可以实现这一点?
谢谢!

你能详细说明一下“文本部分”是什么吗?它是匹配整个文本块还是文本块内的文本?如果您想匹配文本块的某些部分并将其突出显示,您可能需要使用文本运行而不是文本块。请提供更多细节和您的XAML示例。 - Micah
我已经编辑了我的问题。请看一下并告诉我。感谢您的努力 :) - Daniil Harik
2个回答

9

更新:我在这篇博客文章中对这个主题进行了详细阐述。

我认为没有简单的方法来解决这个问题,但是以下是我处理这个问题的方式:

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

以下是我认为可以确定TextBlock的突出显示部分的尺寸的方法:

  1. 通过TextBlock.ContentStart属性获取TextPointer
  2. 使用LogicalDirection.Forwards调用TextPointer.GetPositionAtOffset(indexOfStart)移动到选择的开头。
  3. 使用LogicalDirection.Backwards调用TextPointer.GetPositionAtOffset(indexOfStart)移动到选择的结尾。
  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>

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);
            }
        }
    }
}

我认为这段代码相当容易理解。显然,你需要根据你的具体情况扩展这个概念。你可能更喜欢利用 TextBlockBackground 属性与 DrawingBrushGradientBrush 相结合,而不是使用单独的 Path


好的,我有我的ViewModel。我会尝试从您的想法开始。我会及时向您更新我的进展情况。谢谢您。 - Daniil Harik
哇,深入代码将是一种乐趣。非常感谢...我会让您知道。 - Daniil Harik
非常好的解决方案,我一直在寻找。谢谢。 - Dusan Kocurek

-1

在WPF列表框中进行过滤。以下示例代码对我很有效。

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <TextBox Name="txtSearch" Height="21" Margin="63,12,12,0" VerticalAlignment="Top"></TextBox>
    <ListBox Name="listItems" ItemsSource="{Binding}" Margin="22,0,0,44" Height="179" VerticalAlignment="Bottom" />
</Grid>

Vb.net 代码

将数据表绑定到您的列表框中

Dim _dtable As New DataTable("tblItems") _dtable.Columns.Add("Id", GetType(Integer))
    _dtable.Columns.Add("Name", GetType(String))
    _dtable.Columns.Add("Price", GetType(Double))
    ' Add any initialization after the InitializeComponent() call.
    For i = 100 To 110
        _dtable.Rows.Add(i, "Item " & i, 15.0)
    Next







  Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    listItems.DataContext = _dtable.DefaultView
End Sub
Private Sub txtSearch_TextChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.TextChangedEventArgs) Handles txtSearch.TextChanged

_dtable.DefaultView.RowFilter = "Name like '" & txtSearch.Text & "%'"

的意思是将 _dtable 数据表的默认视图进行筛选,条件为“Name”列以用户在文本框中输入的内容开头。其中 & 符号为连接符。

End Sub

以上示例代码对我有效。

这并不涉及突出显示项目名称的一部分。 - RevitArkitek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接