如何 "restore" Wpf RichTextBox 中的插入符位置?
How do I "restore" the Caret Position in a Wpf RichTextBox?
将我的 RichTextBox 的文本设置为字符串 T 后,RichTextBox 中的插入符位置为 "lost"(它转到它的开头)。这是我正在做的尝试 "restore" 它是 "lost":
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
但是,此代码不起作用。 "restored" 插入符与 "original" 位于不同的位置(由于某种原因总是在 "original" 之后)。
"Saving" RichTextBox 的 CaretPosition 作为 TextPointer 似乎也不起作用。
任何人都可以为我提供 "restoring" 插入符号的替代方法,或修复上述代码的方法吗?
似乎有效(对我而言):
C.CaretPosition = C.Document.ContentStart;
C.CaretPosition = C.CaretPosition.GetPositionAtOffset(CaretIndex, LogicalDirection.Forward);
(顺便说一句,我讨厌 RichTextBox。)
我最近在处理类似的问题,这里有我的解决方案。就我而言,我正在创建一个新的 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);
代码未经测试。我从应用程序的各个部分组装了它。如果您发现任何问题,请告诉我。
在我的情况下,我有一个带有单个段落的 RichTextBox,它只允许输入文本和换行符。我更改了 RichTextBox 的结构(通过创建不同颜色的 运行 实例)但没有更改文本并在更改后恢复。
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;
}
}
将我的 RichTextBox 的文本设置为字符串 T 后,RichTextBox 中的插入符位置为 "lost"(它转到它的开头)。这是我正在做的尝试 "restore" 它是 "lost":
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
但是,此代码不起作用。 "restored" 插入符与 "original" 位于不同的位置(由于某种原因总是在 "original" 之后)。
"Saving" RichTextBox 的 CaretPosition 作为 TextPointer 似乎也不起作用。
任何人都可以为我提供 "restoring" 插入符号的替代方法,或修复上述代码的方法吗?
似乎有效(对我而言):
C.CaretPosition = C.Document.ContentStart;
C.CaretPosition = C.CaretPosition.GetPositionAtOffset(CaretIndex, LogicalDirection.Forward);
(顺便说一句,我讨厌 RichTextBox。)
我最近在处理类似的问题,这里有我的解决方案。就我而言,我正在创建一个新的 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);
代码未经测试。我从应用程序的各个部分组装了它。如果您发现任何问题,请告诉我。
在我的情况下,我有一个带有单个段落的 RichTextBox,它只允许输入文本和换行符。我更改了 RichTextBox 的结构(通过创建不同颜色的 运行 实例)但没有更改文本并在更改后恢复。
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;
}
}