9 Stimmen

Anzeige von Suchergebnissen in einem WPF-Elemente-Steuerelement mit hervorgehobenen Suchbegriffen

Ich möchte Suchergebnisse innerhalb eines WPF ItemsControl mit den Suchbegriffen hervorgehoben anzeigen.

Die Suchmaschine, die ich benutze, Lucene.Net mit dem Highlighter-Plugin, gibt Zeichenketten mit den Suchbegriffen zurück, die wie folgt markiert sind:

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

Ich kann das Highlighter-Plugin anweisen, einen beliebigen Satz von Markup-Tags zu verwenden, um einen Suchbegriff zu umschließen. Ich bin nicht beschränkt auf die <Bold> Tag im obigen Beispiel. Für WPF, würde ich wahrscheinlich machen diese <Run/> Elemente mit einem angehängten Stil.

Die Herausforderung besteht darin, die Zeichenfolge zu nehmen, die mir gegeben wurde, und sie zu rendern, als ob es "tatsächliche XAML" innerhalb der Datenvorlage ist, die ich für Suchergebnisse verwende. Mit anderen Worten, ich möchte etwas wie dieses zu sehen:

...diese Ergebnisse wurden als statistisch signifikant eingestuft...

Aber ich kämpfe mit, wie man Datenbindung mit dynamischen Rendering einer XAML-Zeichenfolge innerhalb des Datatemplates zu kombinieren. Was ist der beste Ansatz hier?

  1. Verwenden Sie ein UserControl, um jedes Suchergebnis anzuzeigen und rufen Sie XamlReader.Load() aus dem Code dahinter?
  2. Konstruieren Sie ein FlowDocument, das die Suchergebnisse enthält, und zeigen Sie die Ergebnisse mit einem FlowDocumentScrollViewer?
  3. Etwas ganz anderes...?

12voto

SyntaxRules Punkte 1778

Ich habe dthrasers Antwort und die Notwendigkeit eines XML-Parsers entfällt. Er leistet großartige Arbeit bei der Erklärung der einzelnen Teile in sein Blog Dazu musste ich jedoch keine zusätzlichen Bibliotheken hinzufügen, wie ich es getan habe.

Schritt eins: Erstellen Sie eine Konverterklasse:

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

Zweiter Schritt: Verwenden Sie anstelle eines TextBlocks einen ContentBlock. Übergeben Sie die Zeichenkette (die Sie für Ihren TextBlock verwenden würden) an den Inhaltsblock, etwa so:

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

Dritter Schritt: Vergewissern Sie sich, dass der Test, den Sie eingeben, mit einem Token versehen ist |~S~| y |~E~| . Und das Hervorheben kann beginnen!

Anmerkungen:
Sie können den Stil im Lauf ändern, um zu bestimmen, was und wie Ihr Text hervorgehoben wird
Stellen Sie sicher, dass Sie Ihre Konverterklasse zu Ihrem Namespace und Ihren Ressourcen hinzufügen. Dies kann auch einen Neuaufbau erfordern, damit es funktioniert.

9voto

dthrasher Punkte 38508

Ich habe eine Möglichkeit gefunden, Suchergebnisse mithilfe eines benutzerdefinierten IValueConverters hervorzuheben. Der Konverter nimmt einen Textausschnitt, formatiert ihn 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, deshalb habe ich sie in meinem Blog veröffentlicht: Hervorhebung von Abfragebegriffen in einem WPF TextBlock

4 Stimmen

Ich bekomme einen 500 Http-Fehler. Könnten Sie (oder jemand anderes) den Link reparieren?

1 Stimmen

Hoppla. Das tut mir leid. Ich habe meine WordPress-Seite wieder in Ordnung gebracht.

1 Stimmen

Der Link ist wieder tot. Ich habe den Link so geändert, dass er auf eine gecachte Version der Seite verweist, nur zur Info.

2voto

Mart Punkte 5258

A TextBlock kann mehrere Run s in seinem Inlines Sammlung. Sie können sie im Code oder in XAML erstellen:

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

0 Stimmen

Meine Frage war wahrscheinlich nicht deutlich genug. Der schwierige Teil ist, dass ich die Zeichenfolge in XAML zur Laufzeit, nicht Kompilierungszeit ändern müssen.

0 Stimmen

Vielleicht habe ich etwas übersehen, aber es sieht für mich machbar, eine XAML-Zeichenfolge wie in meinem Beispiel zu erstellen (mit einigen regulären Ausdruck) und verwenden Sie Ihren ersten Ansatz. Die Lösung, die ich vorgeschlagen habe, war, einen TextBlock zur Laufzeit zu erstellen und seine Inlines-Sammlung mit Runs aufzufüllen. Das Hinzufügen eines Stils zu den hervorgehobenen Runs ist eine Lösung, um FontWeight="Bold" zu ersetzen.

0 Stimmen

Danke, @Mart. Ihre Anregung hat mich auf die richtige Spur gebracht. Meine Antwort beschreibt den Ansatz, den ich verwendet habe.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X