My goal is to double click the entire part of "i.a." like this:
However the default for WPF is it selects each part of the string individually:
Sample:
<RichTextBox>
<FlowDocument>
<Paragraph>Reason for contact: i.a.</Paragraph>
</FlowDocument>
</RichTextBox>
From the users perspective, there may or may not be formatting involved in text to highlight key words, but to simplify this for "i.a.". I don't think any formatting will be involved. The entire "word" may be formatted, but not like the "i" is in red and the "a" is in blue.
What I've found so far
I've attempted to use SpellCheck.CustomDictionaries
, word selection is unaffected by these.
The TextEditorMouse class is responsible starting the selection in SetCaretPositionOnMouseEvent that calls into IsAtCaretUnitBoundary to possibly check word boundaries, but I'm unable to comprehend TextPointer's magic. To me, there doesn't appear to be a way into this as it is guarded off by private and internal methods.
I suspect TextPointer
of CaretPosition
is involved by going forwards and backwards by looking at the calls into System.Windows.Documents.TextPointerBase.GetWordRange(System.Windows.Documents.ITextPointer thisPosition, System.Windows.Documents.LogicalDirection direction)
4:
System.Windows.Documents.TextPointer selectionStart = rtb.CaretPosition;
while (selectionStart.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.Text)
{
selectionStart = selectionStart.GetNextContextPosition(LogicalDirection.Backward);
}
System.Windows.Documents.TextPointer selectionEnd = rtb.CaretPosition;
while (selectionEnd.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)
{
selectionEnd = selectionEnd.GetNextContextPosition(LogicalDirection.Forward);
}
CodePudding user response:
If suppose that the analyzing text does not have formatting consider to use the following code:
private void Rtb_PreviewMouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var tr = GetWordByDelimiters();
// Color the selected text
tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Yellow);
rtb.Focus();
e.Handled = true;
}
public TextRange GetWordByDelimiters()
{
TextPointer current = rtb.CaretPosition;
// \s matches any whitespace character (equivalent to [\r\n\t\f\v ])
string pattern = @"[^\s] "; // Delimiters
// The run content before the current caret position
string backward = current.GetTextInRun(LogicalDirection.Backward);
// Scan text before caret
Match match = Regex.Match(backward, pattern, RegexOptions.RightToLeft);
TextPointer start = current;
if (match.Success && match.Index match.Value.Length == backward.Length)
{
start = start.GetPositionAtOffset(-backward.Length match.Index);
}
// The run content after the current caret position
string forward = current.GetTextInRun(LogicalDirection.Forward);
// Scan text after caret
match = Regex.Match(forward, pattern);
TextPointer end = current;
if (match.Success && match.Index == 0)
{
end = end.GetPositionAtOffset(match.Value.Length, LogicalDirection.Forward);
}
return new TextRange(start, end);
}
Fragments of the .xaml
:
<RichTextBox x:Name="rtb" AllowDrop="True" VerticalScrollBarVisibility="Auto"
PreviewMouseDoubleClick="Rtb_PreviewMouseDoubleClick">
<FlowDocument>
...
</FlowDocument>
</RichTextBox>
If it's necessary modify the pattern
to use any set of delimiters.