2010-09-16 15 views
5

Ich möchte die Suchergebnisse in einem WPF ItemsControl mit hervorgehobenen Abfragebegriffen anzeigen.So zeigen Sie Suchergebnisse in einem WPF-Elementsteuerelement mit hervorgehobenen Abfragebegriffen an

Die Suchmaschine ich benutze, Lucene.Net mit der Highlighter-Plugin, gibt Strings mit den Suchbegriffen wie so markiert:

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

ich den Highlighter Plugin anweisen kann jeden Satz von Markup-Tags zu verwenden, um ein wickeln Suchbegriff abfragen. Ich bin nicht auf den Tag <Bold> im obigen Beispiel beschränkt. Für WPF würde ich wahrscheinlich diese <Run/> Elemente mit einem Stil versehen.

Die Herausforderung besteht darin, die angegebene Zeichenfolge zu nehmen und sie so darzustellen, als wäre sie "tatsächliches XAML" in der Datentabelle, die ich für die Suchergebnisse verwende. Mit anderen Worten, ich möchte so etwas sehen:

... diese Ergebnisse wurden statistisch signifikant sein ...

Aber ich bin zu kämpfen mit, wie zu kombinieren Datenbindung mit dynamischem Rendering eines XAML-Strings innerhalb der Datamaplatte. Was ist der beste Ansatz hier?

  1. Verwenden Sie ein UserControl, um jedes Suchergebnis anzuzeigen, und rufen Sie XamlReader.Load() aus dem Codebehind?
  2. Erstellen Sie ein FlowDocument mit den Suchergebniszeichenfolgen und zeigen Sie die Ergebnisse mit einem FlowDocumentScrollViewer an?
  3. Etwas anderes ganz ...?

Antwort

0

kann ein TextBlock mehr Run s in seiner Inlines Sammlung enthalten. Sie können es im Code oder in XAML bauen:

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

Meine Frage war wahrscheinlich nicht klar genug. Der schwierige Teil ist, dass ich die Zeichenfolge in XAML zur Laufzeit ändern muss, nicht kompilieren Zeit. – dthrasher

+0

Vielleicht habe ich etwas verpasst, aber es ist für mich machbar, eine XAML-Zeichenfolge wie in meinem Beispiel (mit einem regulären Ausdruck) zu erstellen und Ihren ersten Ansatz zu verwenden. Die von mir vorgeschlagene Lösung bestand darin, zur Laufzeit einen TextBlock zu erstellen und seine Inlinesammlung mit Runs zu füllen. Das Hinzufügen eines Stils zu den markierten Runs ist eine Lösung, um FontWeight = "Bold" zu ersetzen. – Mart

+0

Danke, @Mart. Ihr Vorschlag hat mich auf den richtigen Weg gebracht. Meine Antwort beschreibt den Ansatz, den ich verwendet habe. – dthrasher

9

ich einen Weg markiert zutraf eine benutzerdefinierte IValueConverter zu den Suchergebnissen verwenden. Der Konverter nimmt ein Text-Snippet, formatiert es in gültiges XAML-Markup und verwendet einen XamlReader, um das Markup in Framework-Objekte zu instanziieren.

Die vollständige Erklärung ist ziemlich lang, also habe ich es in meinem Blog geschrieben: Highlighting Query Terms in a WPF TextBlock

+0

Ich habe Stil für andere Eigenschaften, aber nicht Hintergrund – Paparazzi

+1

Getting a 500 Http Fehler, könnten Sie (oder jemand anderes) den Link reparieren? –

+0

Whoops. Das tut mir leid. Habe meine WordPress-Seite wieder sortiert. – dthrasher

7

Ich nahm dthrasers answer und nahm die Notwendigkeit für einen XML-Parser aus. Er macht einen tollen Job und erklärt jedes der Stücke in his blog, aber das erforderte nicht, dass ich irgendwelche zusätzlichen Bibliotheken hinzufüge, hier ist, wie ich es gemacht habe.

Schritt eins, einen Konverter Klasse machen:

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

    } 

Schritt zwei: Statt einem Textblock einen ContentBlock verwenden.

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

Schritt drei: Sicherstellen, dass der Test, den Sie in übergeben wird in Token aufgeteilt mit |~S~| und |~E~| Pass in der Zeichenfolge an den Inhaltsblock, wie so (Sie würden für ihren textblock verwendet). Und lass die Hervorhebung beginnen!

Hinweise:
Sie können den Stil im Laufe ändern, um zu bestimmen, was und wie Sie Ihren Text hervorgehoben
Stellen Sie sicher zu Ihrem Namensraum und Ressourcen, um Ihre Converter-Klasse hinzufügen. Dies kann auch eine Wiederherstellung erfordern, um zu funktionieren.