2009-09-21 11 views
15

Ich habe diese WPF RichTextBox und ich möchte einen bestimmten Bereich von Buchstaben/Wörtern programmgesteuert auswählen und markieren. Ich habe das versucht, aber es funktioniert nicht, wahrscheinlich, weil ich einige versteckte FlowDocument-Tags oder ähnliches nicht berücksichtige. Zum Beispiel möchte ich Buchstaben auszuwählen 3-8 aber 2-6 wird gewählt):Wählen Sie Textbereich in WPF RichTextBox (FlowDocument) Programmatisch

var start = MyRichTextBox.Document.ContentStart; 
var startPos = start.GetPositionAtOffset(3); 
var endPos = start.GetPositionAtOffset(8); 
var textRange = new TextRange(startPos,endPos); 
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, 
    new SolidColorBrush(Colors.Blue)); 
textRange.ApplyPropertyValue(TextElement.FontWeightProperty, 
    FontWeights.Bold); 

I RichTextBox Handling realisiert haben, ist ein bisschen schwieriger, als ich dachte :)

Update: Ich habe ein wenige Antworten auf den MSDN-Foren: This thread wo "dekurver" sind:

Die Offsets Sie spezifizieren nicht Zeichen-Offsets aber Symbol-Offsets. Was Sie tun müssen, ist ein TextPointer, den Sie wissen, ist neben zu Text, dann können Sie Zeichen Offsets hinzufügen.

Und „LesterLobo“, sagte:

Sie eine Schleife durch die Absätze und inlines müssen die Weiter zu finden und ihre Offsets dann in einer Schleife für alle Erscheinungen des anzuwenden spezifischer Text. Beachten Sie, dass, wenn Sie bearbeiten Ihr Text würde sich bewegen, aber Ihre Highlight würde nicht bewegen, wie seine mit dem Offset nicht die Text zugeordnet. Sie könnten jedoch eine individuelle Lauf erstellen und ein Highlight für bieten sie ...

würde gerne noch einige Beispiel-Code für diese zu sehen, ob jemand ihren Weg weiß um FlowDocuments ...

EDIT ich habe eine Version von Kratz VB-Code arbeiten, sieht es wie folgt aus:

private static TextPointer GetPoint(TextPointer start, int x) 
{ 
    var ret = start; 
    var i = 0; 
    while (i < x && ret != null) 
    { 
     if (ret.GetPointerContext(LogicalDirection.Backward) == 
TextPointerContext.Text || 
      ret.GetPointerContext(LogicalDirection.Backward) == 
TextPointerContext.None) 
      i++; 
     if (ret.GetPositionAtOffset(1, 
LogicalDirection.Forward) == null) 
      return ret; 
     ret = ret.GetPositionAtOffset(1, 
LogicalDirection.Forward); 
    } 
    return ret; 
} 

Und ich benutze es wie folgt aus:

Colorize(item.Offset, item.Text.Length, Colors.Blue); 

private void Colorize(int offset, int length, Color color) 
{ 
    var textRange = MyRichTextBox.Selection; 
    var start = MyRichTextBox.Document.ContentStart; 
    var startPos = GetPoint(start, offset); 
    var endPos = GetPoint(start, offset + length); 

    textRange.Select(startPos, endPos); 
    textRange.ApplyPropertyValue(TextElement.ForegroundProperty, 
new SolidColorBrush(color)); 
    textRange.ApplyPropertyValue(TextElement.FontWeightProperty, 
FontWeights.Bold); 
} 

Antwort

11
Public Function GoToPoint(ByVal start As TextPointer, ByVal x As Integer) As TextPointer 
    Dim out As TextPointer = start 
    Dim i As Integer = 0 
    Do While i < x 
     If out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.Text Or _ 
      out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.None Then 
      i += 1 
     End If 
     If out.GetPositionAtOffset(1, LogicalDirection.Forward) Is Nothing Then 
      Return out 
     Else 
      out = out.GetPositionAtOffset(1, LogicalDirection.Forward) 
     End If 


    Loop 
    Return out 
End Function 

die Sie interessieren, sollte dies einen Textzeiger für das gegebene Zeichen zurückgeben versetzt. (Tut mir leid, es ist in VB, aber das ist, was ich arbeite in ...)

+0

Schön! Ich habe eine Version dieses Codes funktioniert, werde es der Frage hinzufügen. Prost. –

+0

Dies ist auch praktisch, um die Zeichen in einer RichTextBox zu zählen: mache einfach die Schleife, während "out" nicht null ist, und gebe "i" am Ende zurück. – devios1

+0

Diese Methode holt mich jedes einzelne Zeichen, das nach irgendeinem meiner spezifizierten Zeichen kommt, ich brauche es nur, um einen Zeiger auf mein Wort nur zu erhalten, wenn ich versuche es fett zu machen zum Beispiel macht es den ganzen Satz nach meinem Token "fett" i brauche es nur, um auf meinem Token zu operieren! – a7madx7

7

bereite:

var textRange = MyRichTextBox.Selection; 
var start = MyRichTextBox.Document.ContentStart; 
var startPos = start.GetPositionAtOffset(3); 
var endPos = start.GetPositionAtOffset(8); 
textRange.Select(startPos, endPos); 
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Blue)); 
textRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold); 
+0

Scheint nicht richtig Angst, ich bin zu arbeiten. –

+0

Ich habe es gerade versucht, es funktioniert für mich ... –

+0

@Tomas nicht für mich Ich habe Angst. Die Buchstaben 2-6 werden für mich unter Verwendung dieses Codes ausgewählt/gefärbt. Ich werde etwas anderes versuchen und zurückkommen. –

1

Übrigens (und dies kann akademisch für alle außer mir selbst sein), wenn Sie FocusManager.IsFocusScope = "True" auf den Container der RichTextBox ein Gitter zum Beispiel

<Grid FocusManager.IsFocusScope="True">...</Grid> 

dann sollten Sie in der Lage sein, Johan Danforths Einfärben Verfahren ohne die beiden Anrufungen von ApplyPropertyValue zu verwenden, und die RichTextBox sollte die Standardauswahl Hintergrund und Vordergrund markieren die Auswahl verwenden.

private void Colorize(int offset, int length, Color color) 
{ 
    var textRange = MyRichTextBox.Selection; 
    var start = MyRichTextBox.Document.ContentStart; 
    var startPos = GetPoint(start, offset); 
    var endPos = GetPoint(start, offset + length); 

    textRange.Select(startPos, endPos); 
} 

haben es nicht mit dem RichTextBox versucht, aber es funktioniert ganz gut, wenn sie in einem Flowdocumentreader fündig TextBox Templating. Nur um sicher zu gehen, können Sie auch

<RichTextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">...</RichTextBox> 

setzen, um sicherzustellen, dass die RichTextBox den Fokus innerhalb ihres Fokusbereichs hat.

Der Nachteil davon ist natürlich, dass wenn Sie innerhalb der RichTextBox klicken oder eine Auswahl treffen, Ihre Auswahl verschwindet.

7

Ich habe versucht, die von KratzVB geschriebene Lösung zu verwenden, fand aber, dass es Zeilenumbrüche ignorierte. Wenn Sie zählen möchten \ r \ n Symbole dann sollte dieser Code funktionieren:

private static TextPointer GetPoint(TextPointer start, int x) 
{ 

     var ret = start; 
     var i = 0; 
     while (ret != null) 
     { 
      string stringSoFar = new TextRange(ret, ret.GetPositionAtOffset(i, LogicalDirection.Forward)).Text; 
      if (stringSoFar.Length == x) 
        break; 
      i++; 
      if (ret.GetPositionAtOffset(i, LogicalDirection.Forward) == null) 
       return ret.GetPositionAtOffset(i-1, LogicalDirection.Forward) 

     } 
     ret=ret.GetPositionAtOffset(i, LogicalDirection.Forward); 
     return ret; 
} 
+0

das funktioniert für mich - Sie müssen ein Semikolon nach "return ret.GetPositionAtOffset (i-1, LogicalDirection.Forward)" hinzufügen - Ich habe versucht zu bearbeiten, aber die Bearbeitung ist kürzer als 6 Zeichen (facepalm) –

1

Meine Version basiert auf cave_dweller Version

private static TextPointer GetPositionAtCharOffset(TextPointer start, int numbertOfChars) 
{ 
    var offset = start; 
    int i = 0; 
    string stringSoFar=""; 
    while (stringSoFar.Length < numbertOfChars) 
    { 
     i++; 
     TextPointer offsetCandidate = start.GetPositionAtOffset(
       i, LogicalDirection.Forward); 

     if (offsetCandidate == null) 
      return offset; // ups.. we are to far 

     offset = offsetCandidate; 
     stringSoFar = new TextRange(start, offset).Text; 
    } 

    return offset; 
} 

einige Zeichen diesen Code Looping hinzufügen, um weglassen:

stringSoFar = stringSoFar.Replace("\r\n", "") 
         .Replace(" ", "") 

Statt dessen (langsam):

var startPos = GetPoint(start, offset); 
var endPos = GetPoint(start, offset + length); 

Sie sollten diese (schneller) tun

var startPos = GetPoint(start, offset); 
var endPos = GetPoint(startPos, length); 

Oder erstellen Sie separate Methode Textrange zu bekommen:

private static TextRange GetTextRange(TextPointer start, int startIndex, int length) 
{ 
    var rangeStart = GetPositionAtCharOffset(start, startIndex); 
    var rangeEnd = GetPositionAtCharOffset(rangeStart, length); 
    return new TextRange(rangeStart, rangeEnd); 
} 

Sie können nun Textformat ohne Select() ing:

var range = GetTextRange(Document.ContentStart, 3, 8); 
range.ApplyPropertyValue(
    TextElement.BackgroundProperty, 
    new SolidColorBrush(Colors.Aquamarine)); 
1

nicht finden konnten, eine Lösung mit akzeptabler Performance-Lösung für dieses Problem für eine lange Zeit. Das nächste Beispiel funktioniert in meinem Fall mit der höchsten Leistung. Hoffe, es wird auch jemandem helfen.

TextPointer startPos = rtb.Document.ContentStart.GetPositionAtOffset(searchWordIndex, LogicalDirection.Forward); 
startPos = startPos.CorrectPosition(searchWord, FindDialog.IsCaseSensitive); 
if (startPos != null) 
{ 
    TextPointer endPos = startPos.GetPositionAtOffset(textLength, LogicalDirection.Forward); 
    if (endPos != null) 
    { 
     rtb.Selection.Select(startPos, endPos); 
    } 
} 

public static TextPointer CorrectPosition(this TextPointer position, string word, bool caseSensitive) 
{ 
    TextPointer start = null; 
    while (position != null) 
    { 
     if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text) 
     { 
      string textRun = position.GetTextInRun(LogicalDirection.Forward); 

      int indexInRun = textRun.IndexOf(word, caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase); 
      if (indexInRun >= 0) 
      { 
       start = position.GetPositionAtOffset(indexInRun); 
       break; 
      } 
     } 

     position = position.GetNextContextPosition(LogicalDirection.Forward); 
    } 

    return start; 
} 
0
private TextPointer GetPoint(TextPointer start, int pos) 
    { 
     var ret = start; 
     int i = 0; 
     while (i < pos) 
     { 
      if (ret.GetPointerContext(LogicalDirection.Forward) == 
    TextPointerContext.Text) 
       i++; 
      if (ret.GetPositionAtOffset(1, LogicalDirection.Forward) == null) 
       return ret; 
      ret = ret.GetPositionAtOffset(1, LogicalDirection.Forward); 
     } 
     return ret; 
    } 
+0

Willkommen bei SO und danke für das Posten einer Antwort. Bitte erwägen Sie, Ihre Antwort um eine Erläuterung Ihres Codes zu erweitern. –

Verwandte Themen