Spelling with textboxes and custom dictionaries sl

2020-07-06 09:44发布

问题:

I am using a WPF TextBoxes inside my WinForm application for spell checking. Each time I create one, I load the same file in as a CustomDictionary. All has been fine until recently. Now, they take a long time to load, up to a second. Some forms have 30 or more, meaning delays of nearly half a minute. This seems to be the case Windows 10 (not Windows 8 as I originally posted). The application is running under DotNet 4.0, I have tried 4.5 and 4.6 (not 4.61) and all versions are slow.

I have seen sfaust’s question Spell check textbox in Win10 - Slow and am7zd’s answer. Thanks to these, I looked at the GLOBAL registry key in HKEY_CURRENT_USER\Software\Microsoft\Spelling\Dictionaries. I have 580 entries (after pruning out entries without matching files) and still things are slow.

At present, every time I create a TextBox and add a custom dictionary to it, a new entry seems to be generated in _GLOBAL_

  • Is there a better way of doing things than loading the custom dictionary in from file every time?
  • Is there a way of re-using the same entry in _GLOBAL_ every time instead of creating a new one?
  • Is there a clean way of clearing previous entries in GLOBAL created by my application and their matching .dic files when closing the application (or on restarting it)?
  • I could clear _GLOBAL_ completely each time I start my application. This brings back the speed I want, but what is the downside?

Any advice gratefully received.

回答1:

No answers from anyone else, so this is what I have done:

  1. I made sure I use CustomDictionaries.Remove on all textboxes with custom dictionaries before closing the form they are on. This gets rid of new entries in _GLOBAL_ and the related files in AppData\Local\Temp.

But there will be times when things go wrong or the user just ends the task, leaving _GLOBAL_ entries and .dic files in place, so:

  1. I decided to take things a stage further. When I start my application, I will not only clean entries in _GLOBAL_ that don't have matching files (as suggested in the previous post referenced above), but also to remove all entries referring to .dic files in AppData\Local\Temp. My theory being that anyone who has left entries there didn't mean to, otherwise they would probably have saved the .dic file in a different folder (as Microsoft Office does).

        try
        {
    
            string[] allDictionaries = (string[])Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Spelling\Dictionaries", "_Global_",  new string[0]);
    
            if (allDictionaries.Count() > 0)
            {
                List<string> realDictionaries = new List<string>();
                bool changedSomething = false;
    
                foreach (string thisD in allDictionaries)
                {
                    if (File.Exists(thisD))
                    {
                        if (thisD.Contains(@"\AppData\Local\Temp\"))
                        {
                            // Assuming that anyone who wants to keep a permanent .dic file will not store it in \AppData\Local\Temp
                            // So delete the file and don't copy the name of the dictionary into the list of good dictionaries.
                            File.Delete(thisD);
                            changedSomething = true;
                        }
                        else
                        {
                            realDictionaries.Add(thisD);
                        }
                    }
                    else
                    {
                        // File does not exist, so don't copy the name of the dictionary into the list of good dictionaries.
                        changedSomething = true;
                    }
                }
    
                if (changedSomething)
                {
                    Registry.SetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Spelling\Dictionaries", "_Global_", realDictionaries.ToArray());
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(this, "Error clearing up old dictionary files.\n\nFull message:\n\n" + ex.Message, "Unable to delete file", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    

I am still wondering if it is totally safe to clear entries in _GLOBAL_ that refer to files in AppData\Local\Temp. Surely people shouldn't be leaving important stuff in a temp folder... should they?

What would be really nice would be an overload to CustomDictionaries.Add that allows us to set the name and folder of the .dic file, allowing all the textboxes in the same application to share the same .dic file and making sure we don't leave a load of redundant entries and files with seemingly random names hanging around in the first place..... please Microsoft.