我有这个WPF RichTextBox,我想以编程方式选择给定范围的字母/单词并突出显示它。我试过这个,但它不起作用,可能是因为我没有考虑一些隐藏的FlowDocument标签或类似的东西。例如,我想选择字母3-8但选择2-6):
var start = MyRichTextBox.Document.ContentStart;
var startPos = start.GetPositionAtOffset(3);
var endPos = start.GetPositionAtOffset(8);
var textRange = new TextRange(startPos,endPos);
textRange.ApplyPropertyValue(TextElement.ForegroundProperty,
new SolidColorBrush(Colors.Blue));
textRange.ApplyPropertyValue(TextElement.FontWeightProperty,
FontWeights.Bold);
我意识到RichTextBox处理比我想象的要复杂一点:)
更新:我在MSDN论坛上得到了一些答案:This thread其中“dekurver”seid:
您指定的偏移量不是 字符偏移但符号偏移。 你需要做的是得到一个 你知道的TextPointer是相邻的 到文本,然后你可以添加字符 偏移。
而“LesterLobo”说:
你需要循环使用 段落和内联找到 接下来然后他们在一个循环中的偏移 申请所有的外观 具体文字。请注意,编辑时 你的文字会移动但是你的文字 突出显示不会像它一样移动 与偏移相关联而不是 文本。但是你可以创建一个 自定义运行并提供一个亮点 它...
如果有人知道他们对FlowDocuments的看法,他们仍然愿意看到一些示例代码...
编辑我得到了一个版本的Kratz VB代码,它看起来像这样:
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);
}
答案 0 :(得分:11)
Public Function GoToPoint(ByVal start As TextPointer, ByVal x As Integer) As TextPointer
Dim out As TextPointer = start
Dim i As Integer = 0
Do While i < x
If out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.Text Or _
out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.None Then
i += 1
End If
If out.GetPositionAtOffset(1, LogicalDirection.Forward) Is Nothing Then
Return out
Else
out = out.GetPositionAtOffset(1, LogicalDirection.Forward)
End If
Loop
Return out
End Function
试试这个,这应该返回给定char偏移量的文本指针。 (对不起它在VB中,但那就是我在做什么...)
答案 1 :(得分:8)
试试:
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);
答案 2 :(得分:7)
我尝试使用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;
}
答案 3 :(得分:2)
我的版本基于cave_dweller的版本
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;
}
要省略某些字符,请在循环中添加此代码:
stringSoFar = stringSoFar.Replace("\r\n", "")
.Replace(" ", "")
而不是这个(慢):
var startPos = GetPoint(start, offset);
var endPos = GetPoint(start, offset + length);
你应该这样做(更快)
var startPos = GetPoint(start, offset);
var endPos = GetPoint(startPos, length);
或创建单独的方法来获取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()
的情况下格式化文本:
var range = GetTextRange(Document.ContentStart, 3, 8);
range.ApplyPropertyValue(
TextElement.BackgroundProperty,
new SolidColorBrush(Colors.Aquamarine));
答案 4 :(得分:2)
长时间无法找到具有可接受性能解决方案的解决方案。下一个示例适用于我的情况,性能最高。希望它也会对某人有所帮助。
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;
}
答案 5 :(得分:1)
顺便说一句(如果你在RichTextBox的容器上设置FocusManager.IsFocusScope =“True”,那么就可以学习除了我以外的所有人),例如Grid,
<Grid FocusManager.IsFocusScope="True">...</Grid>
那么你应该可以使用Johan Danforth的Colorize方法而不需要两次调用ApplyPropertyValue,RichTextBox应该使用默认选择Background和Foreground来突出显示选择。
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);
}
没有尝试使用RichTextBox,但在模板化FlowDocumentReader中查找TextBox时效果很好。只是为了确保你也可以设置
<RichTextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">...</RichTextBox>
确保RichTextBox在焦点范围内具有焦点。
当然,这样做的缺点是,如果用户在RichTextBox中单击或执行选择,则您的选择将消失。
答案 6 :(得分:0)
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;
}
答案 7 :(得分:0)
source