2009-09-21 69 views
15

我有這個WPF RichTextBox,我想以編程方式選擇給定範圍的字母/單詞並突出顯示它。我試過這個,但它不起作用,可能是因爲我沒有考慮一些隱藏的FlowDocument標籤或類似的東西。例如,我要選擇字母3-8 2-6,但被選中):以編程方式選擇WPF RichTextBox(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」說:

您需要遍歷 段落和行內找到 下一步,然後他們的偏移在循環 ,申請 的悉數亮相特定的文本。請注意,編輯 時,文字會移動,但您的 高光不會移動爲與 文字相關的偏移而不是 。然而,你可以創建一個自定義的 運行和 它提供的一大亮點......

仍舊愛看到一些這方面的示例代碼,如果有人知道他們的周圍FlowDocuments方式...

編輯我有一個版本的克拉茨VB代碼的工作,它看起來像這樣:

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

我用它是這樣的:

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 

試試這個,這應該返回文本指針定焦偏移。 (對不起,它在VB中,但多數民衆贊成在我的工作...)

+0

不錯!我有一個代碼工作的版本,將其添加到問題中。乾杯。 – 2009-09-28 14:48:27

+0

這對於計算RichTextBox中的字符也很方便:只需執行循環,而「out」不爲空並在最後返回「i」。 – devios1 2010-08-09 01:18:56

+0

這種方法讓我每一個字符後,我的任何指定的令牌後,我只需要它得到一個指向我的單詞的指針,因爲當我嘗試使它粗體例如它使整個句子後我的令牌「大膽」我只需要它來操作我的代幣! – a7madx7 2013-07-23 16:42:44

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

似乎不正常恐怕工作。 – 2009-09-21 13:42:17

+0

我只是試過,它適用於我... – 2009-09-21 15:16:57

+0

@Tomas不適合我恐怕。使用該代碼爲我選擇/着色字母2-6。我要去嘗試別的東西,然後回到這裏。 – 2009-09-21 18:08:36

1

順便說一句(這可能是學術,除了我自己以外),如果你設置FocusManager.IsFocusScope =「True」的RichTextBox的容器,例如電網,

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

,那麼你應該能夠使用約翰丹福斯的彩色化方法,無需ApplyPropertyValue的兩個調用,並在RichTextBox應該使用默認選擇背景和前景突出的選擇。

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

未與RichTextBox的嘗試,但它工作得非常好模板化的FlowDocumentReader一個發現文本框時。只是爲了確保您也可以設置

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

確保RichTextBox具有焦點在其焦點範圍內。

當然,這樣做的缺點是,如果用戶在RichTextBox中單擊或執行選擇,您的選擇就會消失。

7

我嘗試使用KratzVB發佈的解決方案,但發現它忽略了換行符。如果你想數\ r和\ n個符號那麼這段代碼應該工作:

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

這適用於我 - 您需要在「return ret.GetPositionAtOffset(i-1,LogicalDirection.Forward)」之後添加一個分號。我試圖編輯但編輯短於6個字符(facepalm) – 2015-11-03 15:21:52

1

我的版本的基礎上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; 
} 

要省略某些字符添加內循環這樣的代碼:

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

歡迎來到SO並感謝您發佈答案。請考慮擴展您的答案以包含您的代碼的解釋。 – 2016-02-11 18:47:19