C# 文本框拼写检查器检查所有大写单词

C# Texbox Spell Checker Check All Caps Words

使用 WPF 中的文本框拼写检查,它似乎不检查大写单词的拼写。我知道这是为首字母缩略词等设计的,因此它不会将所有这些都标记为拼写错误并且它对此很有用。然而,在我的行业(建筑和工程)中,有许多公司使用所有大写字母来写他们的笔记,所以基本上使拼写检查变得无用......

有什么方法可以改变拼写检查器使其不忽略大写单词吗?

您可以简单地 toLowerCase() 之前的字符串 运行 通过拼写检查器。

好的,所以我终于有时间再试一次,并根据 Tom 的回答想出了一个方法(尽管它并不像那样简单)。我会警告你这绝对是一个黑客......但对于其他为此苦苦挣扎的人来说,它似乎有效。基本上逻辑是这样的:

  • 创建一个从不显示的 'shadow' 文本框并将其文本设置为主文本框的小写版本并启用拼写检查。
  • 根据代码在阴影文本框中搜索拼写错误,并获取框中任何拼写错误的起始位置和长度。
  • 查找找到的字符索引与主文本框的相对位置。
  • 使用装饰层为任何拼写错误的单词添加红色下划线。
  • 每当文本更改或框的大小更改时,更新文本并重新运行以上内容。

我有点担心性能,但我的应用程序中有相当多的文本框,而且在使用它时我没有注意到任何减速。这是代码:

在文本框中加载处理程序:

            //Create a shadow textbox to run spell check in - set text to the lower version of main text 
            TextBox tbSpell = new TextBox();
            tbSpell.Text = tb.Text.ToLower();

            //Enable spelling on the shadow box if we have spell checking enabled
            tbSpell.SpellCheck.IsEnabled = tb.DataContext is KeynoteVM && (tb.DataContext as KeynoteVM).EnableSpelling;

            //Set the shadow as a tag to the main textbox so we have access to it directly
            tb.Tag = tbSpell;

            //Adde handlers for size change or text change as we may need to update adorners
            tb.SizeChanged += tb_SizeChanged;
            tb.TextChanged += tb_TextChanged;

大小和文本更改处理程序只需调用如下所示的更新方法:

        //Remove existing adorners
        AdornerLayer lyr = AdornerLayer.GetAdornerLayer(tb);
        if (lyr != null)
        {
            Adorner[] ads = lyr.GetAdorners(tb);
            if (ads != null)
            {
                foreach (Adorner ad in lyr.GetAdorners(tb))
                { lyr.Remove(ad); }
            }
        }

        //Get the shadow textbox from the tag property
        TextBox tbSpell = tb.Tag as TextBox;
        if (tbSpell == null || !tbSpell.SpellCheck.IsEnabled)
        { return; }

        //Make sure we have the latest text
        tbSpell.Text = tb.Text.ToLower();

        //Loop to get all spelling errors starting at index 0
        int indx = 0;
        while (true)
        {
            //Find the spelling error
            indx = tbSpell.GetNextSpellingErrorCharacterIndex(indx, LogicalDirection.Forward);
            if (indx > -1)
            {
                //Have a match, get the length of the error word
                int len = tbSpell.GetSpellingErrorLength(indx);

                //Get a rectangle describing the position of the error to use for drawing the underline
                Rect r = tb.GetRectFromCharacterIndex(indx);
                Rect rEnd = tb.GetRectFromCharacterIndex(indx + len);

                //Modify the rectangle width to the width of the word
                r.Width = rEnd.Right - r.Right;

                //Create an adorner for the word and set the 'draw location' property to the rectangle
                AdornerSpell ad = new AdornerSpell(tb);
                ad.drawLocation = r;

                //Add the adorner to the textbox
                AdornerLayer.GetAdornerLayer(tb).Add(ad);

                //Increment the index to move past this word
                indx += len;
            }
            else
            { break; }
        }

这是我创建的装饰器 class 的代码(它只是用红色下划线):

public class AdornerSpell : Adorner
{
    public Rect drawLocation { get; set; }
    public AdornerSpell(UIElement adornedElement) : base(adornedElement) { }

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
    {
        drawingContext.DrawLine(new System.Windows.Media.Pen(new SolidColorBrush(Colors.Red), 1), drawLocation.BottomLeft, drawLocation.BottomRight);
    }
}

当然,如果您使用右键单击获取建议,则必须修改它以从阴影文本框而不是常规文本框获取建议。

我发现的唯一问题是,由于它总是检查小写字母,因此它会识别像 I've 和 I'll 这样的拼写错误,因为 I 应该大写。我敢肯定也有办法解决这个问题,但我还没有尝试过。

无论如何,它不是很确定,但它似乎有效,如果不完全创建一个新的拼写检查系统,我找不到更好的东西......如果有人有其他建议,我仍然愿意接受,但这个至少是可行的。

编辑:

意识到我实际上可以通过告诉它在调度程序上使用 'BeginInvoke' 更新为异步 运行 来进一步降低性能影响。现在文本更改和大小更改方法如下所示:

Dispatcher.BeginInvoke(new Action(() => UpdateSpellingAdorners(sender as TextBox)));