2010-04-02 14 views
8

Ich habe eine WPF RichTextBox, in die ich etwas Text eintippe und dann den gesamten Text analysiere, um die Verarbeitung durchzuführen. Während dieses Parsens habe ich die absoluten Zeichenpositionen von Anfang und Ende jedes Wortes.WPF FlowDocument - Absolute Zeichenposition

Ich möchte diese Zeichenpositionen verwenden, um die Formatierung bestimmter Wörter anzuwenden. Ich habe jedoch festgestellt, dass das FlowDocument TextPointer-Instanzen verwendet, um Positionen im Dokument zu markieren.

Ich habe festgestellt, dass ich ein TextRange erstellen kann, indem Sie es mit Start- und Endzeigern konstruieren. Sobald ich den TextRange habe, kann ich leicht Formatierung auf den Text darin anwenden. Ich habe GetPositionAtOffset verwendet, um einen TextPointer für meinen Zeichenoffset zu bekommen, aber ich vermute, dass sein Offset sich von meinem unterscheidet, weil der ausgewählte Text in einer etwas anderen Position als erwartet ist.

Meine Frage ist, wie kann ich eine absolute Zeichenposition genau in einen TextPointer konvertieren?

+1

+1, ich habe genau dieses Problem - individuelle Analyse zu tun und die Highlights sind falsch Offset :-) – Cameron

Antwort

5

Ich habe keine zuverlässige Möglichkeit gefunden, absolute Zeichenpositionen in TextPosition-Instanzen zu konvertieren.

Meine alternative Lösung bestand darin, das ursprüngliche Parsing so zu ändern, dass es an einzelnen Läufen arbeitet, anstatt den gesamten Text der RichTextBox zu erfassen. Das Arbeiten mit Zeichenpositionen, die relativ zu einer bestimmten Run-Instanz sind, hat sich für mich als zuverlässig erwiesen. Ich denke, dass es mir geholfen hat, meine Denkweise stärker auf die Denkweise von WPF zu übertragen.

Ich nahm den folgenden Ansatz für die Läufe in der Flowdocument (inspiriert von http://blogs.msdn.com/prajakta/archive/2006/10/12/customize-richtextbox-to-allow-only-plain-text-input.aspx) Navigation:

// Get starting pointer 
TextPointer navigator = flowDocument.ContentStart; 

// While we are not at end of document 
while (navigator.CompareTo(flowDocument.ContentEnd) < 0) 
{ 
    // Get text pointer context 
    TextPointerContext context = navigator.GetPointerContext(LogicalDirection.Backward); 

    // Get parent as run 
    Run run = navigator.Parent as Run; 

    // If start of text element within run 
    if (context == TextPointerContext.ElementStart && run != null) 
    { 
     // Get text of run 
     string runText = run.Text; 

     // ToDo: Parse run text 
    } 

    // Get next text pointer 
    navigator = navigator.GetNextContextPosition(LogicalDirection.Forward); 
} 
1

Ich hatte genau das gleiche Problem, ich fand heraus, dass es einen Fehler in RichTextBox gibt, weil es nicht "neue Zeile Zeichen - \ r \ n" zählt, so wie Ihre Zeilennummern erhöhen, finden Sie, dass Ihr Offset ist Falsch nach Zeilenanzahl positioniert, und ich hatte meine Probleme gelöst, indem ich die Zeilennummer vom Offset versetzte.

+0

Hallo Akash, Vielen Dank für Ihre Antwort. Meine Erfahrung ist, dass es meine neuen Zeilenzeichen zählt, aber bemerkt habe, dass komplett leere Zeilen "" bewirken, dass das FlowDocument aus 2 Zeichen besteht vor meinen Offsets (kumulativ nach jedem Zeilenumbruch). Alan –

3

Ich habe dieses Problem auch hatte und hat mit der folgenden RichTextBox-Extension-Methode endete. In meinem Kontext funktioniert es einwandfrei!

/// <summary> 
/// Gets the text pointer at the given character offset. 
/// Each line break will count as 2 chars. 
/// </summary> 
/// <param name="richTextBox">The rich text box.</param> 
/// <param name="offset">The offset.</param> 
/// <returns>The TextPointer at the given character offset</returns> 
public static TextPointer GetTextPointerAtOffset(this RichTextBox richTextBox, int offset) 
{ 
    var navigator = richTextBox.Document.ContentStart; 
    int cnt = 0; 

    while (navigator.CompareTo(richTextBox.Document.ContentEnd) < 0) 
    { 
     switch (navigator.GetPointerContext(LogicalDirection.Forward)) 
     { 
      case TextPointerContext.ElementStart: 
       break; 
      case TextPointerContext.ElementEnd: 
       if (navigator.GetAdjacentElement(LogicalDirection.Forward) is Paragraph) 
        cnt += 2; 
       break; 
      case TextPointerContext.EmbeddedElement: 
       // TODO: Find out what to do here? 
       cnt++; 
       break; 
      case TextPointerContext.Text: 
       int runLength = navigator.GetTextRunLength(LogicalDirection.Forward); 

       if (runLength > 0 && runLength + cnt < offset) 
       { 
        cnt += runLength; 
        navigator = navigator.GetPositionAtOffset(runLength); 
        if (cnt > offset) 
         break; 
        continue; 
       } 
       cnt++; 
       break; 
     } 

     if (cnt > offset) 
      break; 

     navigator = navigator.GetPositionAtOffset(1, LogicalDirection.Forward); 

    } // End while. 

    return navigator; 
} 
Verwandte Themen