2010-09-16 4 views
5

Me gustaría mostrar los resultados de búsqueda dentro de WPF ItemsControl con los términos de consulta resaltados.Cómo mostrar resultados de búsqueda en un control de elementos de WPF con términos de consulta resaltados

El motor de búsqueda que utilizo, Lucene.Net con el plugin de resaltado, devuelve cadenas con los términos de la consulta remarcados así:

...these <Bold>results</Bold> were found to be statistically significant... 

me puede dar instrucciones al plug-in de resaltado de utilizar cualquier conjunto de etiquetas de marcado para envolver un término de consulta. No estoy limitado a la etiqueta <Bold> en el ejemplo anterior. Para WPF, probablemente haga estos elementos <Run/> con un estilo adjunto.

El reto es tomar la cadena que me han dado y presentarla como si fuera "XAML real" dentro de la plantilla de datos que estoy usando para los resultados de búsqueda. En otras palabras, quiero ver algo como esto:

... estos resultados fueron, fueron hallados lleguen a ser competentes ...

Pero estoy luchando con la forma de combinar enlace de datos con representación dinámica de una cadena XAML dentro de la plantilla de datos. ¿Cuál es el mejor enfoque aquí?

  1. Use un UserControl para mostrar cada resultado de búsqueda y llame al XamlReader.Load() desde el código subyacente?
  2. ¿Construye un FlowDocument que contiene las cadenas de resultados de búsqueda y muestra los resultados con un FlowDocumentScrollViewer?
  3. ¿Algo más enteramente ...?

Respuesta

0

A TextBlock puede contener múltiples Run s en su colección Inlines. Se puede construir en clave o en XAML:

<TextBlock> 
    <Run>... these </Run> 
    <Run FontWeight="Bold">results</Run> 
    <Run> were found...</Run> 
</TextBlock> 
+0

Mi pregunta probablemente no era lo suficientemente clara. La parte difícil es que tengo que cambiar la cadena en XAML en tiempo de ejecución, no en tiempo de compilación. – dthrasher

+0

Tal vez me perdí algo pero me parece factible construir una cadena XAML como en mi ejemplo (con algunas expresiones regulares) y utilizar su primer enfoque. La solución que sugerí fue construir un TextBlock en tiempo de ejecución y completar su colección Inlines con Runs. Agregar un estilo a Runs resaltado es una solución para reemplazar FontWeight = "Bold". – Mart

+0

Gracias, @Mart. Tu sugerencia me puso en el camino correcto. Mi respuesta describe el enfoque que utilicé. – dthrasher

9

he encontrado una manera aplicar el resaltado resultados usando un IValueConverter de búsqueda personalizados. El convertidor toma un fragmento de texto, lo formatea en marcado XAML válido y usa un XamlReader para instanciar el marcado en objetos de marco.

La explicación completa es bastante largo, por lo que he publicado a mi blog: Highlighting Query Terms in a WPF TextBlock

+0

Obtuve el estilo para trabajar con otras propiedades pero no con el fondo – Paparazzi

+1

Obteniendo un error de 500 Http, ¿podría usted (u otra persona) reparar el enlace? –

+0

Whoops. Lo siento por eso. Conseguí mi sitio de WordPress ordenado de nuevo. – dthrasher

7

Tomé dthrasers answer y saqué la necesidad de un analizador XML. Él hace un gran trabajo explicando cada una de las piezas en his blog, Sin embargo, esto no me obligó a agregar bibliotecas adicionales, así es como lo hice.

primer paso, hacer una clase convertidor:

class StringToXamlConverter : IValueConverter 
    { 

     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      string input = value as string; 
      if (input != null) 
      { 
       var textBlock = new TextBlock(); 
       textBlock.TextWrapping = TextWrapping.Wrap; 
       string escapedXml = SecurityElement.Escape(input); 

       while (escapedXml.IndexOf("|~S~|") != -1) { 
       //up to |~S~| is normal 
       textBlock.Inlines.Add(new Run(escapedXml.Substring(0, escapedXml.IndexOf("|~S~|")))); 
       //between |~S~| and |~E~| is highlighted 
       textBlock.Inlines.Add(new Run(escapedXml.Substring(escapedXml.IndexOf("|~S~|") + 5, 
              escapedXml.IndexOf("|~E~|") - (escapedXml.IndexOf("|~S~|") + 5))) 
              { FontWeight = FontWeights.Bold, Background= Brushes.Yellow }); 
       //the rest of the string (after the |~E~|) 
       escapedXml = escapedXml.Substring(escapedXml.IndexOf("|~E~|") + 5); 
       } 

       if (escapedXml.Length > 0) 
       { 
        textBlock.Inlines.Add(new Run(escapedXml));      
       } 
       return textBlock; 
      } 

      return null; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      throw new NotImplementedException("This converter cannot be used in two-way binding."); 
     } 

    } 

Paso dos: En lugar de un TextBlock utilizar un ContentBlock. Ir a la cadena (que le de utilizado para su textBlock) al bloque de contenidos, así:

<ContentControl 
       Margin="7,0,0,0" 
       HorizontalAlignment="Left" 
       VerticalAlignment="Center" 
       Content="{Binding Description, Converter={StaticResource CONVERTERS_StringToXaml}, Mode=OneTime}"> 
</ContentControl> 

Paso tres: Asegúrese de que la prueba se pasa en tokenized está con |~S~| y |~E~|. ¡Y que comience el resaltado!

Notas:
Puede cambiar el estilo en la carrera para determinar qué y cómo el texto se resalta
asegúrese de agregar la clase Converter para el espacio de nombres y de los recursos. Esto también podría requerir una reconstrucción para que funcione.

Cuestiones relacionadas