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

时间:2009-04-28 15:35:34

标签: .net wpf xaml listbox highlighting

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

ListBox绑定到CollectionViewSource。

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

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

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

我认为不可能使用DataTemplates。

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

谢谢!

2 个答案:

答案 0 :(得分:9)

更新:我在this blog post中详细阐述了这个主题。

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

  1. 为列表中的项目定义视图模型。它应该包含公开文本的属性,并定义文本的哪一部分应该突出显示(基本上是开始和结束索引)。
  2. 当用户在搜索框中输入文本时,请查看视图模型并检查文本中的匹配项。如果找到匹配项,请相应地设置索引。如果未找到匹配项,请将索引设置回-1或任何表示不匹配的内容。
  3. 在您的视图中,将Background的{​​{1}}设置为索引。使用转换器将索引转换为两个索引之间为亮黄色(或其他)的TextBlock
  4. 以下是我认为的方法,您可以找出GradientBrush突出显示部分的尺寸:

    1. 通过TextBlock媒体资源获取TextPointer
    2. 使用TextBlock.ContentStart
    3. 调用TextPointer.GetPositionAtOffset(indexOfStart),转到选择的开头
    4. 使用LogicalDirection.Forwards
    5. 调用TextPointer.GetPositionAtOffset(indexOfStart),移至选择的末尾
    6. 致电LogicalDirection.Backwards以获取突出显示内容的边界TextPointer.GetCharacterRect
    7. 说实话,我不确定最后一点是否有效。我必须自己尝试一下,我可以为博客发帖。

      编辑:有时间为自己试一试。它确实有效,尽管我的逻辑略有改变。下面是演示的代码。这是一个截图:

      Screenshot http://img219.imageshack.us/img219/2969/searchx.png

      Window1.xaml

      Rectangle

      Window1.xaml.cs

      <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>
      

      我认为代码是相当不言自明的。显然,您需要将概念扩展到您的特定场景。您可能更愿意利用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); } } } } 的{​​{1}}属性与BackgroundTextBlock相结合,而不是使用单独的DrawingBrush

答案 1 :(得分:0)

在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'”&amp; txtSearch.Text&amp; “%'”

End Sub
  

以上示例代码适用于我