簡體   English   中英

如何在 Wpf RichTextBox 中“恢復”插入符號位置?

[英]How do I “restore” the Caret Position in a Wpf RichTextBox?

將 RichTextBox 的文本設置為字符串 T 后,RichTextBox 中的插入符號位置“丟失”(它轉到它的開頭)。 這是我在“丟失”后嘗試“恢復”它的方法:

public static int GetCaretIndex(RichTextBox C)
{
    return new TextRange(C.Document.ContentStart, C.CaretPosition).Text.Length;
}
...
int CaretIndex = GetCaretIndex(C); // Get the Caret position before setting the text of the RichTextBox
new TextRange(C.Document.ContentStart, C.Document.ContentEnd).Text = T; // Set the text of the RichTextBox
C.CaretPosition = C.Document.ContentStart.GetPositionAtOffset(CaretIndex, LogicalDirection.Forward); // Set the Caret Position based on the "Caret Index" variable

但是,此代碼不起作用。 “恢復的”插入符號與“原始”插入符號的位置不同(由於某種原因,它總是在“原始”插入符號后面)。

“保存” RichTextBox 的 CaretPosition 作為 TextPointer 似乎也不起作用。

任何人都可以為我提供“恢復”插入符號的替代方法,或者修復上述代碼的方法?

我最近正在處理類似的問題,這是我的解決方案。 就我而言,我正在創建一個新的 RichTextBox.Document 內容,當我這樣做時,我想保留插入符號位置。

我的想法是插入符號偏移函數是有偏差的,這要歸功於用於文本表示(段落、運行等)的數據結構,這些數據結構也以某種方式計算偏移位置。

TextRange 是一種在文本中獲得准確插入符號位置的好方法。 問題在於它的修復。 但是當我知道我的文檔是從哪些組件構建的時,事情就變得容易了。 就我而言,只有段落和運行。

剩下的就是訪問文檔結構,找到插入符號應該在的確切運行並將插入符號設置為找到的運行的正確位置。

代碼:

// backup caret position in text
int backPosition = 
    new TextRange(RichTextBox.CaretPosition.DocumentStart, RichTextBox.CaretPosition).Text.Length;

// set new content (caret position is lost there)
RichTextBox.Document.Blocks.Clear();
SetNewDocumentContent(RichTextBox.Document);

// find position and run to which place caret
int pos = 0; Run caretRun = null;
foreach (var block in RichTextBox.Document.Blocks)
{
    if (!(block is Paragraph para))
        continue;

    foreach (var inline in para.Inlines){
    {
        if (!(inline is Run run))
            continue;

        // find run to which place caret
        if (caretRun == null && backPosition > 0)
        {
            pos += run.Text.Length;
            if (pos >= backPosition){
                 caretRun = run;
                 break;
            }
        }
    }

    if (caretRun!=null)
        break;
}

// restore caret position
if (caretRun != null)
    RichTextBox.CaretPosition = 
        caretRun.ContentEnd.GetPositionAtOffset(backPosition - pos, LogicalDirection.Forward);

代碼沒有經過測試。 我從我的應用程序的各個部分組裝它。 如果您發現任何問題,請告訴我。

似乎工作(對我來說): C.CaretPosition = C.Document.ContentStart; C.CaretPosition = C.CaretPosition.GetPositionAtOffset(CaretIndex, LogicalDirection.Forward); C.CaretPosition = C.Document.ContentStart; C.CaretPosition = C.CaretPosition.GetPositionAtOffset(CaretIndex, LogicalDirection.Forward);

(順便說一下,我討厭 RichTextBox。)

在我的情況下,我有一個帶有單個段落的 RichTextBox,它只允許輸入文本和換行符。 我更改了 RichTextBox 的結構(通過創建不同顏色的 Run 實例)但不更改文本並在更改后恢復。

public static class CaretRestorer
{
    public static void Restore(RichTextBox richTextBox, Action changer)
    {
        var caretPosition = GetCaretPosition(richTextBox);
        changer();
        Restore(richTextBox, caretPosition);
    }
    private static string GetFullText(RichTextBox richTextBox)
    {
        return new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd).Text;
    }
    private static int GetInlineTextLength(Inline inline)
    {
        if(inline is LineBreak)
        {
            return 2;
        }
        return new TextRange(inline.ContentStart, inline.ContentEnd).Text.Length;
    }
    private static void Restore(RichTextBox richTextBox,int caretPosition)
    {
        var inlines = GetInlines(richTextBox);
        var accumulatedTextLength = 0;
        foreach (var inline in inlines)
        {
            var inlineTextLength = GetInlineTextLength(inline);
            var newAccumulatedTextLength = accumulatedTextLength + inlineTextLength;
            if (newAccumulatedTextLength >= caretPosition)
            {
                TextPointer newCaretPosition = null;
                if(inline is LineBreak)
                {
                    newCaretPosition = inline.ContentEnd;
                }
                else
                {
                    var diff = caretPosition - accumulatedTextLength;
                    newCaretPosition = inline.ContentStart.GetPositionAtOffset(diff);
                }
                
                richTextBox.CaretPosition = newCaretPosition;
                break;
            }
            else
            {
                accumulatedTextLength = newAccumulatedTextLength;
            }
        }
    }
    private static int GetCaretPosition(RichTextBox richTextBox)
    {
        return new TextRange(richTextBox.Document.ContentStart, richTextBox.CaretPosition).Text.Length;
    }

    

    private static Paragraph GetParagraph(RichTextBox RichTextBox)
    {
        return RichTextBox.Document.Blocks.FirstBlock as Paragraph;
    }
    private static InlineCollection GetInlines(RichTextBox RichTextBox)
    {
        return GetParagraph(RichTextBox).Inlines;
    }
}

暫無
暫無

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

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