【问题标题】:How do I "restore" the Caret Position in a Wpf RichTextBox?如何“恢复” Wpf RichTextBox 中的插入符号位置?
【发布时间】:2017-05-28 21:08:47
【问题描述】:

在将我的 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 似乎也不起作用。

谁能为我提供“恢复”插入符号的替代方法,或修复上述代码的方法?

【问题讨论】:

  • 您检索索引并设置位置。根据文档,它们并不相同。尝试保存插入符号位置而不是插入符号索引。您似乎要替换整个内容-如果有新文本,恢复插入符号有什么意义?特别是,如果插入符号在结尾附近出现,并且新文本更短,会发生什么情况?
  • @dlatikay 尝试将 CaretPosition 保存为 TextPointer 会使“恢复的”指针指向 RichTextBox 的开头。我正在为撤消/重做系统替换整个内容(请参阅:stackoverflow.com/questions/15772602/…)。要回答您的第二个问题,似乎没有任何“不同”发生,插入符号只是转到“原始”插入符号行上方的段落,或者返回几个字符。

标签: c# .net wpf richtextbox caret


【解决方案1】:

似乎工作(对我来说): C.CaretPosition = C.Document.ContentStart; C.CaretPosition = C.CaretPosition.GetPositionAtOffset(CaretIndex, LogicalDirection.Forward);

(顺便说一句,我讨厌 RichTextBox。)

【讨论】:

  • 那(出于某种奇怪的原因)“效果更好”。当新文本更改文本大小时仍然遇到一些麻烦,但我很确定通过一些游戏我可以让它工作(一旦我开始工作就会在这里发布)。 “顺便说一句,我讨厌 RichTextBox。” - 你不是唯一的。
  • 这很简短,很明显,而且切中要害。只是希望 CaretPosition 没有设置两次,但我愿意接受。
【解决方案2】:

我最近正在处理类似的问题,并且有我的解决方案。就我而言,我正在创建一个新的 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);

代码未经测试。我从我的应用程序的各个部分组装它。如果您发现任何问题,请告诉我。

【讨论】:

    【解决方案3】:

    在我的情况下,我有一个带有单个段落的 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多