C# 以编程方式选择WPF RichTextBox(FlowDocument)中的文本范围
我有一个WPF RichTextBox,我想通过编程选择给定范围的字母/单词并突出显示它。我已经试过了,但它不起作用,可能是因为我没有考虑一些隐藏的FlowDocument标签或类似的内容。例如,我想选择字母3-8,但选择了字母2-6): 我意识到RichTextBox的处理比我想象的要复杂一些:) 更新:我在MSDN论坛上得到了一些答案:“dekurver”seid: 您正在指定的偏移不正确 字符偏移,但符号偏移。 你需要做的是找一个 您知道的文本指针是相邻的 到文本,然后可以添加字符 补偿 “LesterLobo”说: 您将需要通过 段落和内联以查找 然后在循环中单击它们的偏移 申请 具体文本。请注意,当您编辑 你的文字会移动,但你的 高亮显示不会移动,因为其 与偏移量关联,而不是与 文本。但是,您可以创建一个 自定义运行,并为 它 如果有人知道如何处理流程文档,我仍然希望看到一些示例代码 编辑我得到了一个版本的Kratz VB代码,它看起来像这样:C# 以编程方式选择WPF RichTextBox(FlowDocument)中的文本范围,c#,wpf,richtextbox,C#,Wpf,Richtextbox,我有一个WPF RichTextBox,我想通过编程选择给定范围的字母/单词并突出显示它。我已经试过了,但它不起作用,可能是因为我没有考虑一些隐藏的FlowDocument标签或类似的内容。例如,我想选择字母3-8,但选择了字母2-6): 我意识到RichTextBox的处理比我想象的要复杂一些:) 更新:我在MSDN论坛上得到了一些答案:“dekurver”seid: 您正在指定的偏移不正确 字符偏移,但符号偏移。 你需要做的是找一个 您知道的文本指针是相邻的 到文本,然后可以添加字符 补偿
private static TextPointer GetPoint(TextPointer start, int x)
{
var ret = start;
var i = 0;
while (i < x && ret != null)
{
if (ret.GetPointerContext(LogicalDirection.Backward) ==
TextPointerContext.Text ||
ret.GetPointerContext(LogicalDirection.Backward) ==
TextPointerContext.None)
i++;
if (ret.GetPositionAtOffset(1,
LogicalDirection.Forward) == null)
return ret;
ret = ret.GetPositionAtOffset(1,
LogicalDirection.Forward);
}
return ret;
}
Colorize(item.Offset, item.Text.Length, Colors.Blue);
private void Colorize(int offset, int length, Color color)
{
var textRange = MyRichTextBox.Selection;
var start = MyRichTextBox.Document.ContentStart;
var startPos = GetPoint(start, offset);
var endPos = GetPoint(start, offset + length);
textRange.Select(startPos, endPos);
textRange.ApplyPropertyValue(TextElement.ForegroundProperty,
new SolidColorBrush(color));
textRange.ApplyPropertyValue(TextElement.FontWeightProperty,
FontWeights.Bold);
}
试试看:
var textRange = MyRichTextBox.Selection;
var start = MyRichTextBox.Document.ContentStart;
var startPos = start.GetPositionAtOffset(3);
var endPos = start.GetPositionAtOffset(8);
textRange.Select(startPos, endPos);
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Blue));
textRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
Public函数GoToPoint(ByVal start作为TextPointer,ByVal x作为Integer)作为TextPointer
当text指针=开始时变暗
尺寸i为整数=0
当我
尝试此操作,这将返回给定字符偏移量的文本指针。(很抱歉,这是在VB中,但这正是我正在使用的…顺便说一句(这可能对我以外的所有人来说都是学术性的),如果您在RichTextBox的容器上设置FocusManager.IsFocusScope=“True”,例如网格
<Grid FocusManager.IsFocusScope="True">...</Grid>
我还没有尝试过RichTextBox,但是在FlowDocumentReader中模板化find TextBox时,它工作得非常好。只是为了确定你也可以设置
<RichTextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">...</RichTextBox>
。。。
确保RichTextBox在其焦点范围内具有焦点
当然,这样做的缺点是,如果用户在RichTextBox中单击或执行选择,您的选择就会消失。我尝试使用KratzVB发布的解决方案,但发现它忽略了换行符。如果要计数\r和\n符号,则此代码应起作用:
private static TextPointer GetPoint(TextPointer start, int x)
{
var ret = start;
var i = 0;
while (ret != null)
{
string stringSoFar = new TextRange(ret, ret.GetPositionAtOffset(i, LogicalDirection.Forward)).Text;
if (stringSoFar.Length == x)
break;
i++;
if (ret.GetPositionAtOffset(i, LogicalDirection.Forward) == null)
return ret.GetPositionAtOffset(i-1, LogicalDirection.Forward)
}
ret=ret.GetPositionAtOffset(i, LogicalDirection.Forward);
return ret;
}
我的版本基于洞穴居住者的版本
private static TextPointer GetPositionAtCharOffset(TextPointer start, int numbertOfChars)
{
var offset = start;
int i = 0;
string stringSoFar="";
while (stringSoFar.Length < numbertOfChars)
{
i++;
TextPointer offsetCandidate = start.GetPositionAtOffset(
i, LogicalDirection.Forward);
if (offsetCandidate == null)
return offset; // ups.. we are to far
offset = offsetCandidate;
stringSoFar = new TextRange(start, offset).Text;
}
return offset;
}
而不是这个(慢):
你应该这样做(更快)
或创建单独的方法以获取TextRange:
private static TextRange GetTextRange(TextPointer start, int startIndex, int length)
{
var rangeStart = GetPositionAtCharOffset(start, startIndex);
var rangeEnd = GetPositionAtCharOffset(rangeStart, length);
return new TextRange(rangeStart, rangeEnd);
}
您现在可以格式化文本,而无需Select()
ing:
var range = GetTextRange(Document.ContentStart, 3, 8);
range.ApplyPropertyValue(
TextElement.BackgroundProperty,
new SolidColorBrush(Colors.Aquamarine));
很长一段时间无法找到具有可接受性能的解决方案解决此问题。下一个示例适用于我的情况,具有最高的性能。希望它也能帮助别人
TextPointer startPos = rtb.Document.ContentStart.GetPositionAtOffset(searchWordIndex, LogicalDirection.Forward);
startPos = startPos.CorrectPosition(searchWord, FindDialog.IsCaseSensitive);
if (startPos != null)
{
TextPointer endPos = startPos.GetPositionAtOffset(textLength, LogicalDirection.Forward);
if (endPos != null)
{
rtb.Selection.Select(startPos, endPos);
}
}
public static TextPointer CorrectPosition(this TextPointer position, string word, bool caseSensitive)
{
TextPointer start = null;
while (position != null)
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
string textRun = position.GetTextInRun(LogicalDirection.Forward);
int indexInRun = textRun.IndexOf(word, caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase);
if (indexInRun >= 0)
{
start = position.GetPositionAtOffset(indexInRun);
break;
}
}
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
return start;
}
private TextPointer GetPoint(TextPointer start,int pos)
{
var-ret=开始;
int i=0;
while(i
@Tomas恐怕不适合我。字母2-6使用该代码为我选择/着色。我要试试别的东西回来。谢谢你——我知道我要么要设置.Selection
,要么要调用.Select(…)
——但必须调用.Selection.Select
?完全出乎意料,是的。这项工作,我有一个问题,由于MyRichTextBox的重点。因此,如果有任何问题,首先以编程方式关注它,(MyRichTextBox.focus())。很好!我得到了一个版本的代码,将它添加到问题中。干杯。这对于计算RichTextBox中的字符也很方便:只需在out
不为null时执行循环,并在结尾返回i
。此方法可以让我获得任何指定标记后面的每个字符,我只需要它来获取指向我的单词的指针,因为当我尝试将其设置为粗体时,例如,它就是在我的代币“bold”后生成整个句子我只需要它来操作我的代币!就像VisualStudio使用其保留的关键字一样!这不适用于单个字符或两个相邻的元素。这适用于我-您需要在“return ret.GetPositionAtOffset(i-1,LogicalDirection.Forward)”后添加分号-我尝试编辑,但编辑长度小于6个字符(facepalm)。欢迎使用SO,感谢您发布答案。请考虑扩展您的答案,包括对代码的解释。请将您的答案始终放在上下文中,而不只是粘贴代码。有关更多详细信息,请参阅。
var startPos = GetPoint(start, offset);
var endPos = GetPoint(start, offset + length);
var startPos = GetPoint(start, offset);
var endPos = GetPoint(startPos, length);
private static TextRange GetTextRange(TextPointer start, int startIndex, int length)
{
var rangeStart = GetPositionAtCharOffset(start, startIndex);
var rangeEnd = GetPositionAtCharOffset(rangeStart, length);
return new TextRange(rangeStart, rangeEnd);
}
var range = GetTextRange(Document.ContentStart, 3, 8);
range.ApplyPropertyValue(
TextElement.BackgroundProperty,
new SolidColorBrush(Colors.Aquamarine));
TextPointer startPos = rtb.Document.ContentStart.GetPositionAtOffset(searchWordIndex, LogicalDirection.Forward);
startPos = startPos.CorrectPosition(searchWord, FindDialog.IsCaseSensitive);
if (startPos != null)
{
TextPointer endPos = startPos.GetPositionAtOffset(textLength, LogicalDirection.Forward);
if (endPos != null)
{
rtb.Selection.Select(startPos, endPos);
}
}
public static TextPointer CorrectPosition(this TextPointer position, string word, bool caseSensitive)
{
TextPointer start = null;
while (position != null)
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
string textRun = position.GetTextInRun(LogicalDirection.Forward);
int indexInRun = textRun.IndexOf(word, caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase);
if (indexInRun >= 0)
{
start = position.GetPositionAtOffset(indexInRun);
break;
}
}
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
return start;
}
private TextPointer GetPoint(TextPointer start, int pos)
{
var ret = start;
int i = 0;
while (i < pos)
{
if (ret.GetPointerContext(LogicalDirection.Forward) ==
TextPointerContext.Text)
i++;
if (ret.GetPositionAtOffset(1, LogicalDirection.Forward) == null)
return ret;
ret = ret.GetPositionAtOffset(1, LogicalDirection.Forward);
}
return ret;
}
private void SelectText(int start, int length)
{
TextRange textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
TextPointer pointerStart = textRange.Start.GetPositionAtOffset(start, LogicalDirection.Forward);
TextPointer pointerEnd = textRange.Start.GetPositionAtOffset(start + length, LogicalDirection.Backward);
richTextBox.Selection.Select(pointerStart, pointerEnd);
}