2009-09-21 27 views
15

私はこのWPFのRichTextBoxを持っていると私はプログラム的に文字/単語の与えられた範囲を選択し、それを強調表示します。私はこれを試しましたが、うまくいきません。なぜなら、いくつかの隠されたFlowDocumentタグなどを考慮していないからです。例えば、私は)文字3-8を選択したいが、2-6が選択されます:私が得た:選択範囲(FlowDocument)プログラム

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); 

私はRichTextBoxの処理を実現してきたことは、私は:)

更新を考えていたよりも少し複雑ですMSDNフォーラムには、いくつかの答え:This thread「dekurver」SEID:

あなたが指定しているオフセットは 文字オフセットが、シンボルオフセットではありません。あなたがする必要がどのような は、あなたが知っている のTextPointerがテキストに 隣接している取得、その後、あなたは文字 オフセットを追加することができます。

そして「LesterLoboは、」言った:

あなたが のすべての外観を申請するループ で 次、次にそのオフセットを見つけるために 段落やインラインをループにする必要があります

特定のテキストあなたが移動する あなたのテキストを編集するが、ときに ハイライトはオフセットない テキストに関連付けられているその として動くwouldntのことに注意してください。ただしEDIT

...

はまだ誰かがFlowDocumentsの周りに彼らの方法を知っている場合は、このためのいくつかのサンプルコードを見てみたい... カスタムランを作成し、 のためにそれをハイライトを提供することができ

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; 
} 

そして、私はこのようにそれを使用します:私が働いてKratz VBコードのバージョンを持って、それはこのようになります

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

答えて

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 

は、このオフセットを指定されたcharのテキストポインタを返す必要があり、これを試してみてください。 (VBで申し訳ありませんが、私がやっていることは...)

+0

ニース!私はそのコードのバージョンが動作している、それを質問に追加します。乾杯。 –

+0

これは、RichTextBoxの文字をカウントするのにも便利です: 'out'がヌルでないときにループを行い、最後に' i'を返します。 – devios1

+0

このメソッドは、私が指定したトークンの後に来るすべての文字を取得します。私はそれが私のトークンのポインタを取得する必要があるだけです。私のトークンを操作するだけです!ビジュアルスタジオのような – a7madx7

7

はそれを試してみてください。

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

が正しく、私は怖い動作するようには思えません。 –

+0

私はちょうど試みた、それは私のために働く... –

+0

@トーマス私のためではない私は恐れている。 2〜6文字がそのコードを使って私のために選択/色付けされます。私は別のものを試してここに戻ります。 –

1

ちなみに、RichTextBoxのコンテナにFocusManager.IsFocusScope = "True"を設定すると例えば、グリッドは、

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

あなたはApplyPropertyValueの2つの呼び出しなしヨハン・ダンフォースの色付け方法を使用することができるはず、とリッチテキストボックスには、選択を強調するために、デフォルトの選択の背景と前景を使用するべきです。

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

は、リッチテキストボックスでそれを試していないが、FlowDocumentReaderで検索テキストボックスをテンプレート化するとき、それはかなりうまく動作します。リッチテキストボックスのフォーカス範囲内にフォーカスがあることを確認するには、

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

を指定することもできます。

もちろん、ユーザーがリッチテキストボックス内で選択をクリックまたは実行すると、選択が消えてしまうという欠点があります。

7

私はKratzVBが投稿した解決策を試しましたが、改行を無視していました。あなたは、\ rと\ n個のシンボルをカウントしたい場合、このコードは動作するはずです:いくつかの文字を省略するcave_dwellerのバージョン

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; 
} 

に基づいて

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

(「アウト」は予約語なので、もちろん、私は変数に改名しました) - 私は編集しようとしましたが、編集は6文字(facepalm)未満です –

1

私のバージョンでは、ループ内でこのコードを追加します。

これに代えて
stringSoFar = stringSoFar.Replace("\r\n", "") 
         .Replace(" ", "") 

(遅い):

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

あなたがこの(速い)

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

またはTextRangeのを取得するために別のメソッドを作成して実行する必要があります。

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

あなたは今Select() INGのない形式のテキストことができます。

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

が見つかりませんでしたが長い間、この問題に対する許容可能な性能の解決策を有する解決策である。私の場合、次のサンプルは最高のパフォーマンスで動作します。それが誰かにも役立つことを願っています。

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

ようこそ、と答えを投稿していただきありがとうございます。コードの説明を含めるように答えを拡大することを検討してください。 –

関連する問題