【问题标题】:RichTextBox double click selecting words separated by periods like "i.a."RichTextBox 双击选择由句点分隔的单词,如“i.a.”
【发布时间】:2021-12-28 05:36:03
【问题描述】:

我的目标是双击“i.a.”的整个部分像这样:

但是 WPF 的默认设置是单独选择字符串的每个部分:

示例:

<RichTextBox>
    <FlowDocument>
        <Paragraph>Reason for contact: i.a.</Paragraph>
    </FlowDocument>
</RichTextBox>

从用户的角度来看,文本中可能包含或不包含用于突出显示关键词的格式,但为了简化“i.a.”。我认为不会涉及任何格式。整个“word”可以被格式化,但不像“i”是红色的,“a”是蓝色的。

到目前为止我发现了什么

我尝试使用SpellCheck.CustomDictionaries,单词选择不受这些影响。

TextEditorMouse 类负责在调用 IsAtCaretUnitBoundary 的 SetCaretPositionOnMouseEvent 中启动选择以检查单词边界,但我无法理解 TextPointer 的魔力。对我来说,似乎没有办法解决这个问题,因为它受到私有和内部方法的保护。

通过查看对System.Windows.Documents.TextPointerBase.GetWordRange(System.Windows.Documents.ITextPointer thisPosition, System.Windows.Documents.LogicalDirection direction)4的调用,我怀疑CaretPosition中的TextPointer参与了前进和后退:

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);
}

【问题讨论】:

标签: c# wpf richtextbox


【解决方案1】:

如果假设分析文本没有格式化考虑使用以下代码:

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);
}     

.xaml的片段:

  <RichTextBox x:Name="rtb" AllowDrop="True" VerticalScrollBarVisibility="Auto" 
          PreviewMouseDoubleClick="Rtb_PreviewMouseDoubleClick">
      <FlowDocument>
            ...
      </FlowDocument>
  </RichTextBox>

如果有必要修改pattern 以使用任何一组分隔符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 2020-05-18
    • 2012-11-08
    • 1970-01-01
    • 2015-01-16
    相关资源
    最近更新 更多