WPF RichTextBox无法进行拼写检查

3
我正在尝试在WPF RichTextBox中启用拼写检查。 MSDN写道,System.Windows.Controls.SpellCheck 可以用于为TextBox和RichTextBox控件启用拼写检查。
不幸的是,以下代码对我无效:
<RichTextBox SpellCheck.IsEnabled="True" xml:lang="en-US"></RichTextBox>

这很奇怪,因为如果我使用普通的TextBox,它可以完美地工作(如果我拼错了什么,我可以看到红线)。

不幸的是,到目前为止我在SO上找到的每个 答案都只提到将SpellCheck.IsEnabled设置为True并将Language属性设置为支持的语言之一,但我不知道为什么这种方法在内置的RichTextBox上不起作用?

更新:

如果我写下这个,run中的文本将被下划线标记:

<RichTextBox SpellCheck.IsEnabled="True">
    <FlowDocument Language="en">
         <Paragraph>
             <Run>asdfasdf</Run>
         </Paragraph>
    </FlowDocument>
</RichTextBox>

但不幸的是,如果我尝试输入其他文本,它将被忽略。看起来编辑后的内容中属性Language没有设置为英语。我已经尝试设置ThreadCurrentCultureCurrentUICulture,但没有结果...


你能给我一些提示,你在什么环境下测试?如操作系统版本、.NET Framework 版本等。 - Zsolt
这不是一个有效的FlowDocument,对我来说会抛出语法错误。第一级元素必须从Block驱动,而Run不行。尝试使用有效的第一级元素,例如段落(Paragraph)。 - paparazzo
是的,你说得对,我已经编辑了我的问题。段落部分在将代码复制粘贴到StackOverflow帖子后不知何故丢失了。 - Zsolt
1个回答

6

好的,最终我已经找到了解决问题的方法。如果你深入挖掘WPF源码,就可以很容易地看到问题所在:有一个名为TextEditorTyping的内部类,它有一个名为DoTextInput的方法,负责插入用户输入的字符。该方法通过在TextEditor上调用SetSelectedText来设置插入范围的区域属性(TextEditor是另一个内部类,为各种控件提供文本编辑服务,如RichTextBox)。以下是DoTextInput方法的一部分:

IDisposable disposable = This.Selection.DeclareChangeBlock();
using (disposable)
{
    ITextSelection selection = This.Selection;
    if (!This.AllowOvertype || !This._OvertypeMode)
    {
         flag = false;
    }
    else
    {
         flag = str != "\t";
    }
    ((ITextRange)selection).ApplyTypingHeuristics(flag);
    // SETTING THE CULTURE ->
    This.SetSelectedText(str, InputLanguageManager.Current.CurrentInputLanguage);
    ITextPointer textPointer = This.Selection.End.CreatePointer(LogicalDirection.Backward);
    This.Selection.SetCaretToPosition(textPointer, LogicalDirection.Backward, true, true);
    undoCloseAction = UndoCloseAction.Commit;
}

因此,该方法使用InputLanguageManager.Current.CurrentInputLanguage,它对应于Windows中的当前输入语言。如果您使用的输入语言与英语(FrameworkElement.LanguageProperty的默认值)不同,则如果您在RichTextBox中编辑文本,则插入FlowDocument中的元素将具有其Language属性作为当前输入语言。例如,如果您的输入语言是匈牙利语(hu-hu),则您的FlowDocument将如下所示:

<FlowDocument>
     <Paragraph>
         <Run xml:lang="hu-hu">asdfasdf</Run>
     </Paragraph>
</FlowDocument>

这个网站描述了同样的问题。

幸运的是,我们有一个解决方法。我们已经看到了DoTextInput方法的源代码,并且在其中有一个using块:

IDisposable disposable = This.Selection.DeclareChangeBlock();
using (disposable)
{
    ...
    // SETTING THE CULTURE ->
    This.SetSelectedText(str, InputLanguageManager.Current.CurrentInputLanguage);
    ...
}

这是一个变化块,它在最后一行被处理 - 处理后,将触发 TextContainerChanged 事件,我们可以通过重写 RichTextBoxOnTextChanged 方法来处理它:

protected override void OnTextChanged(TextChangedEventArgs e)
{
    var changeList = e.Changes.ToList();
    if (changeList.Count > 0)
    {
        foreach (var change in changeList)
        {
            TextPointer start = null;
            TextPointer end = null;
            if (change.AddedLength > 0)
            {
                start = this.Document.ContentStart.GetPositionAtOffset(change.Offset);
                end = this.Document.ContentStart.GetPositionAtOffset(change.Offset + change.AddedLength);
            }
            else
            {
                int startOffset = Math.Max(change.Offset - change.RemovedLength, 0);
                start = this.Document.ContentStart.GetPositionAtOffset(startOffset);
                end = this.Document.ContentStart.GetPositionAtOffset(change.Offset);
            }

            if (start != null && end != null)
            {
                var range = new TextRange(start, end);
                range.ApplyPropertyValue(FrameworkElement.LanguageProperty, Document.Language);
            }
        }
    }
    base.OnTextChanged(e);
}

在这里,我们正在将编辑范围的语言重置为正确的值 - 即 Document.Language。 完成此解决方法后,您可以使用WPF拼写检查 - 例如,用法语:
<My:CultureIndependentRichTextBox xml:lang="fr-FR" SpellCheck.IsEnabled="True">
     <FlowDocument>
     </FlowDocument>
</My:CultureIndependentRichTextBox>

它会神奇地工作。:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接