簡體   English   中英

如何在WPF RichTextBox中跟蹤TextPointer?

[英]How to keep track of TextPointer in WPF RichTextBox?

我試圖讓我了解WPF RichTextBox中的TextPointer類。

我希望能夠跟蹤它們,以便可以將信息與文本中的區域相關聯。

我目前正在使用一個非常簡單的示例來嘗試弄清楚發生了什么。 在PreviewKeyDown事件中,我存儲插入符位置,然后在PreviewKeyUp事件中,基於插入符位置之前和之后創建TextRange。 這是一個代碼示例,它說明了我正在嘗試執行的操作:

// The caret position before typing
private TextPointer caretBefore = null;

private void rtbTest_PreviewKeyDown(object sender, KeyEventArgs e)
{
    // Store caret position
    caretBefore = rtbTest.CaretPosition;
}

private void rtbTest_PreviewKeyUp(object sender, KeyEventArgs e)
{
    // Get text between before and after caret positions
    TextRange tr = new TextRange(caretBefore, rtbTest.CaretPosition);
    MessageBox.Show(tr.Text);
}

問題是我得到的文本為空白。 例如,如果我鍵入字符“ a”,那么我希望在TextRange中找到文本“ a”。

有人知道出什么事了嗎? 這可能很簡單,但是我花了一個下午無所事事。

我試圖擁抱新的WPF技術,但是發現RichTextBox特別復雜,以至於即使做這樣的簡單事情也很困難。 如果有人有任何鏈接可以很好地解釋TextPointer,請告訴我,我們將不勝感激。

當您在FlowDocument中添加和刪除文本時,所有TextPointer都會根據多種啟發式方法來調整其位置,這些啟發式方法旨在使它們停留在盡可能靠近同一“位置”的位置。

對於刪除而言,這很簡單:如果TextPointer在刪除的文本中,則它將終止於刪除的文本周圍的字符之間。 但是對於插入而言,並不是那么簡單:當將文本或其他元素恰好在現有TextPointer處插入到FlowDocument中時,TextPointer應該在插入的文本之前還是之后結束? TextPointer具有一個稱為“ LogicalDirection”的屬性來控制此屬性。

在您的情況下,正在捕獲的“ caretBefore”位置正好是插入鍵入字符的TextPosition,在您的測試案例中,您的LogicalDirection是LogicalDirection.Forward。 因此,當插入字符時,您的“ caretBefore”在插入的字符之后結束,這與TextPosition一致,為您提供了一個空的TextRange。

TextPointer如何獲得分配給它的LogicalDirection? 如果單擊RichTextBox來設置插入標記的位置,則單擊將被解釋為介於兩個字符之間。 如果您單擊的實際點在第二個字符上,則將LogicalDirection設置為“前進”,但是如果您單擊的實際點在第一個字符上,則將LogicalDirection設置為“后退”。

試試這個實驗:

  1. 設置您的FontSize =“ 40”並在構造函數中用文本“ ABCD”預先填充RichTextBox
  2. 單擊B的右側,然后在B和C之間鍵入“ X”。LogicalDirection是Backward,因此您的“ beforeCaret”在“ X”之前結束,並且MessageBox顯示“ X”。
  3. 單擊C的左側,然后在B和C之間鍵入“ X”。LogicalDirection是Forward,因此您的“ beforeCaret”在“ X”之后結束,並且MessageBox為空。

此行為是違反直覺的:當您不知道存在LogicalDirection時,您會認為單擊B的右側或C的左側將獲得完全相同的插入符位置。

注意:可視化發生情況的一種簡單方法是發出MessageBox.Show,然后執行caretBefore.InsertTextInRun("^");

您如何獲得所需的結果? LogicalDirection是只讀的。 一種方法是使用TextRange來強制構造LogicalDirection為Backward的TextPointer:

caretBefore = new TextRange(caretBefore, caretBefore.DocumentEnd).Start;

在PreviewKeyDown中執行此操作。 如果您等到PreviewKeyUp,則為時已晚:caretBefore已移動。 之所以可行,是因為據我所知,非空TextRange的Start始終具有Backward的LogicalDirection。

另一種選擇是從文檔的開頭保存符號偏移量(請注意,這不是字符偏移量!)。 在這種情況下,您可以將偏移量存儲在PreviewKeyDown中:

caretBeforeOffset = caretBefore.DocumentStart.OffsetToPosition(caretBefore);

並將caretBefore重置為PreviewKeyUp中的相同符號偏移量:

caretBefore = caretBefore.DocumentStart.GetPositionAtOffset(caretBeforeOffset,
                                                            LogicalDirection.Forward);

盡管此方法有效,但不像強迫TextPointer具有向后的LogicalDirection那樣通用:在文檔中的PreviewKeyDown和PreviewKeyUp之間的任何較早文本更改都會導致符號偏移量計算找到錯誤的位置,這是TextPointers設計的目的首先解決。

除了閱讀文檔並與他們一起玩之外,我不知道用於學習TextPointers的任何有用資源,而這正是您已經在做的事情。

對我TextPointer before = yourRichTextBox.CaretPosition.GetPositionAtOffset(-1, LogicalDirection.Backward); 為了獲得字符的位置,該字符位於插入符號之前。 然后,可以得到TextRange用於與插入的字符TextRange range = new TextRange(before, yourRichTextBox.CaretPosition); (使用before時,您應該檢查null ,因為如果插入符號前沒有任何內容,它將為null

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM