C# “我该怎么做?”;“恢复”;Wpf RichTextBox中的插入符号位置?
将我的RichTextBox的文本设置为字符串T后,RichTextBox中的插入符号位置将“丢失”(它将转到它的开头)。以下是我在“丢失”后尝试“恢复”它所做的工作: 但是,此代码不起作用。“恢复的”插入符号与“原始”插入符号处于不同的位置(出于某些原因,始终位于“原始”插入符号的后面) 将RichTextBox的CaretPosition“保存”为文本指针似乎也不起作用 有谁能为我提供一种“恢复”插入符号的替代方法,或修复上述代码的方法吗?似乎对我有效:C# “我该怎么做?”;“恢复”;Wpf RichTextBox中的插入符号位置?,c#,.net,wpf,richtextbox,caret,C#,.net,Wpf,Richtextbox,Caret,将我的RichTextBox的文本设置为字符串T后,RichTextBox中的插入符号位置将“丢失”(它将转到它的开头)。以下是我在“丢失”后尝试“恢复”它所做的工作: 但是,此代码不起作用。“恢复的”插入符号与“原始”插入符号处于不同的位置(出于某些原因,始终位于“原始”插入符号的后面) 将RichTextBox的CaretPosition“保存”为文本指针似乎也不起作用 有谁能为我提供一种“恢复”插入符号的替代方法,或修复上述代码的方法吗?似乎对我有效: C.CaretPosition=C
C.CaretPosition=C.Document.ContentStart;
C.CaretPosition=C.CaretPosition.GetPositionAtOffset(CaretIndex,LogicalDirection.Forward)代码>
(顺便说一句,我讨厌RichTextBox。)我最近处理了一个类似的问题,这就是我的解决方案。在我的例子中,我正在创建一个新的RichTextBox.documentcontent,当我这样做时,我希望保持插入符号的位置
我的想法是,插入符号偏移函数是有偏差的,这要感谢用于文本表示(段落、运行…)的数据结构,它们也以某种方式计算偏移位置
TextRange是获得文本中插入符号精确位置的好方法。问题在于它的恢复。但当我知道我的文档是从哪个组件构建的时,它就变得容易了。在我的例子中,只有段落和段落
剩下的就是访问文档结构,找到插入符号应该在的确切位置,并将插入符号设置为找到的运行的正确位置
代码:
代码没有经过测试。我从应用程序的各个部分组装了它。如果您发现任何问题,请告诉我。在我的情况下,我有一个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;
}
}
检索索引并设置位置。根据文献记载,它们并不相同。尝试保存插入符号位置而不是插入符号索引。您似乎正在替换整个内容-如果有新文本,恢复插入符号有什么意义?特别是,如果插入符号在接近尾端时较暗,而新文本较短,该怎么办?@dlatikay尝试将插入符号位置保存为文本指针,会使“还原”的指针转到RichTextBox的开头。我正在替换撤消/重做系统的全部内容(请参阅)。为了回答你的第二个问题,似乎没有什么“不同”,插入符号只是转到“原始”插入符号行上的段落,或者返回几个字符。这(出于某种奇怪的原因)“效果更好”。当新文本改变文本大小时仍然有一些问题,但我非常确定,通过一些游戏,我可以使它工作(我一开始工作,就会把它张贴在这里)。“顺便说一句,我讨厌RichTextBox。”-你不是唯一一个。
// 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);
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;
}
}