以编程方式选择WPF RichTextBox(FlowDocument)中的文本范围
我有这个WPF RichTextBox,我想以编程方式选择给定范围的字母/单词并突出显示它。我试过这个,但它不起作用,可能是因为我没有考虑一些隐藏的FlowDocument标签或类似的东西。例如,我要选择字母3-8 2-6,但被选中):以编程方式选择WPF RichTextBox(FlowDocument)中的文本范围
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方式...
编辑我有一个版本的克拉茨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);
}
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
试试这个,这应该返回文本指针定焦偏移。 (对不起,它在VB中,但多数民众赞成在我的工作...)
试一下:
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);
似乎不正常恐怕工作。 – 2009-09-21 13:42:17
我只是试过,它适用于我... – 2009-09-21 15:16:57
@Tomas不适合我恐怕。使用该代码为我选择/着色字母2-6。我要去尝试别的东西,然后回到这里。 – 2009-09-21 18:08:36
顺便说一句(这可能是学术,除了我自己以外),如果你设置FocusManager.IsFocusScope =“True”的RichTextBox的容器,例如电网,
<Grid FocusManager.IsFocusScope="True">...</Grid>
,那么你应该能够使用约翰丹福斯的彩色化方法,无需ApplyPropertyValue的两个调用,并在RichTextBox应该使用默认选择背景和前景突出的选择。
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一个发现文本框时。只是为了确保您也可以设置
<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;
}
这适用于我 - 您需要在“return ret.GetPositionAtOffset(i-1,LogicalDirection.Forward)”之后添加一个分号。我试图编辑但编辑短于6个字符(facepalm) – 2015-11-03 15:21:52
我的版本的基础上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()
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 = 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;
}
欢迎来到SO并感谢您发布答案。请考虑扩展您的答案以包含您的代码的解释。 – 2016-02-11 18:47:19
不错!我有一个代码工作的版本,将其添加到问题中。干杯。 – 2009-09-28 14:48:27
这对于计算RichTextBox中的字符也很方便:只需执行循环,而“out”不为空并在最后返回“i”。 – devios1 2010-08-09 01:18:56
这种方法让我每一个字符后,我的任何指定的令牌后,我只需要它得到一个指向我的单词的指针,因为当我尝试使它粗体例如它使整个句子后我的令牌“大胆”我只需要它来操作我的代币! – a7madx7 2013-07-23 16:42:44