2009-04-28 8 views
3

J'ai un TextBox et un ListBox. L'utilisateur peut rechercher des éléments ListBox à partir de TextBox.WPF Listbox surligner une partie de l'élément ListBoxItem

ListBox est lié à CollectionViewSource. CollectionViewSource dispose d'un gestionnaire d'événements Filter, qui filtre les éléments en fonction du texte saisi par l'utilisateur dans TextBox.

Mon exigence est de mettre en évidence le texte saisi par l'utilisateur dans TextBlock des éléments ListBoxItem.

Je pensais casser le TextBlock en plusieurs objets Runs et modifier la propriété Background des objets Run qui doivent être mis en surbrillance.

Je pense que ce n'est pas possible avec DataTemplates.

Existe-t-il un moyen facile d'accomplir ceci?

Merci!

+0

Faisable? Oui! ... Facile? Non!! – Micah

+0

Pouvez-vous donner plus de détails sur les "parties de texte"? Correspond-il à un bloc de texte ou à un texte dans un bloc de texte? Si vous essayez de faire correspondre des parties d'un bloc de texte et de le mettre en surbrillance, vous ne pourrez pas le faire sans utiliser un texte au lieu d'un bloc de texte. S'il vous plaît donner plus de détails et peut-être un échantillon de votre xaml. – Micah

+0

J'ai modifié ma question. S'il vous plaît jeter un oeil et faites le moi savoir. Merci pour votre effort :) –

Répondre

9

MISE À JOUR: J'élaboré de manière significative à ce sujet dans this blog post.

Je ne pense pas qu'il y ait un moyen facile de le faire, mais voici comment je résoudre ce problème:

  1. Définir un modèle de vue pour les éléments de la liste. Il devrait inclure des propriétés pour exposer le texte et définir quelle partie du texte devrait être mise en évidence (les index de début et de fin, fondamentalement).
  2. Lorsque l'utilisateur saisit du texte dans la zone de recherche, parcourez les modèles de vue et recherchez les correspondances dans le texte. Si une correspondance est trouvée, définissez les index de manière appropriée. Si une correspondance est introuvable, redéfinissez les index sur -1 ou tout ce qui ne correspond à aucune correspondance. À votre avis, définissez le Background du TextBlock sur les index. Utilisez un convertisseur pour convertir les index en GradientBrush qui est jaune vif (ou peu importe) entre les deux index.

Voilà comment Je pense que vous pouvez comprendre les dimensions des parties soulignées du TextBlock:

  1. Obtenir un TextPointer via la propriété TextBlock.ContentStart.
  2. Déplacez au début de la sélection en appelant TextPointer.GetPositionAtOffset(indexOfStart) en utilisant LogicalDirection.Forwards.
  3. Déplacez-vous à la fin de la sélection en appelant TextPointer.GetPositionAtOffset(indexOfStart) en utilisant LogicalDirection.Backwards.
  4. Appelez TextPointer.GetCharacterRect pour obtenir la bordure Rectangle du contenu en surbrillance.

Pour être honnête, je ne suis pas sûr que ce dernier travail. Je devrais l'essayer pour moi-même, et je peux le faire pour un billet de blog.

EDIT: Juste eu le temps d'essayer par moi-même. Cela fonctionne vraiment, bien qu'avec de légères modifications à ma logique ci-dessus. Voici le code qui démontre.Voici une capture d'écran:

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

Je pense que le code est assez auto explicatif. Évidemment, vous devrez étendre le concept à votre scénario particulier. Vous pouvez préférer tirer parti de la propriété Background du TextBlock combinée avec un DrawingBrush ou GradientBrush au lieu d'avoir le Path distinct.

+0

OK, j'ai mon ViewModel. Je vais essayer de commencer avec votre idée. Je vous tiendrai au courant de mes progrès. Je vous remercie. –

+0

Wow. Ce sera un plaisir de creuser dans le code. Merci beaucoup ... Je vous le ferai savoir –

+0

Très belle solution que je cherchais. Merci. –

0

Filtrage dans la zone de liste WPF. suivant Exemple de code fonctionne très bien pour moi.

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

liant datatable dans votre Listbox

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 = "nom comme « & txtSearch .Texte & "% '"

End Sub 

Au-dessus exemple de code fonctionne pour moi

Questions connexes