2010-09-16 13 views
5

Vorrei visualizzare i risultati di ricerca all'interno di un oggetto WPF ItemsControl con i termini della query evidenziati.Come visualizzare i risultati di ricerca in un controllo di elementi WPF con termini di query evidenziati

Il motore di ricerca che uso, Lucene.Net con il plugin evidenziatore, restituisce le stringhe con i termini della query marcato in questo modo:

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

mi può istruire il plugin Highlighter di utilizzare qualsiasi set di tag di markup per avvolgere una termine della query. Non sono limitato al tag <Bold> nell'esempio sopra. Per WPF, probabilmente creerò questi elementi <Run/> con uno stile allegato.

La sfida è prendere la stringa che ho ricevuto e renderla come se fosse "XAML reale" all'interno del datatemplate che sto usando per i risultati di ricerca. In altre parole, voglio vedere qualcosa di simile:

... questi risultati sono stati sono risultate essere statisticamente significativo ...

Ma sto lottando con il modo di coniugare associazione dati con rendering dinamico di una stringa XAML all'interno del datatemplate. Qual è l'approccio migliore qui?

  1. Utilizzare un controllo utente per visualizzare ogni risultato di ricerca e chiamare XamlReader.Load() dal codebehind?
  2. Costruire un oggetto FlowDocument contenente le stringhe dei risultati di ricerca e visualizzare i risultati con un FlowDocumentScrollViewer?
  3. Qualcos'altro interamente ...?

risposta

0

Un TextBlock può contenere più Run s nella sua collezione Inlines. È possibile costruire in codice o in XAML:

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

La mia domanda probabilmente non era abbastanza chiara. La parte difficile è che ho bisogno di cambiare la stringa in XAML in fase di esecuzione, non in fase di compilazione. – dthrasher

+0

Forse mi sono perso qualcosa, ma mi sembra possibile costruire una stringa XAML come nel mio esempio (con alcune espressioni regolari) e utilizzare il tuo primo approccio. La soluzione che ho suggerito era di creare un TextBlock in fase di runtime e compilare la sua collezione Inlines con Runs. Aggiungere uno stile alle corse evidenziate è una soluzione per sostituire FontWeight = "Grassetto". – Mart

+0

Grazie, @Mart. Il tuo suggerimento mi ha messo sulla strada giusta. La mia risposta descrive l'approccio che ho usato. – dthrasher

9

ho trovato un modo per applicare l'evidenziazione di risultati utilizzando un IValueConverter ricerca personalizzata. Il convertitore prende uno snippet di testo, lo formatta in un markup XAML valido e utilizza un XamlReader per creare un'istanza del markup in oggetti framework.

La spiegazione completa è piuttosto lungo, quindi ho postato sul mio blog: Highlighting Query Terms in a WPF TextBlock

+0

Ho ottenuto lo stile di lavorare per altre proprietà ma non lo sfondo – Paparazzi

+1

Ottenere un errore di 500 Http, potresti (o qualcun altro) risolvere il collegamento? –

+0

Whoops. Mi dispiace per quello Ho ottenuto il mio sito WordPress ordinato di nuovo. – dthrasher

7

ho preso dthrasers answer e tirai fuori la necessità di un parser XML. Fa un ottimo lavoro spiegando ognuno dei pezzi in his blog, tuttavia questo non mi ha richiesto di aggiungere altre librerie, ecco come l'ho fatto.

Fase uno, fare una classe convertitore:

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

    } 

Fase due: Invece di un TextBlock utilizzare un ContentBlock. Passare nella stringa (si sarebbe di utilizzare per il vostro textBlock) al blocco di contenuti, in questo modo:

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

Fase tre: Assicurarsi il test si passa è tokenized con |~S~| e |~E~|. E cominciamo l'evidenziazione!

Note:
È possibile modificare lo stile nella corsa per determinare cosa e come il testo viene evidenziato
Assicurati di aggiungere la classe Converter per lo spazio dei nomi e delle risorse. Questo potrebbe richiedere anche una ricostruzione per funzionare.

Problemi correlati