Spell check textbox in Win10 - Slow
Asked Answered
T

3

4

I'm using the built in spell checker in WPF. It was working just fine until I had users start upgrading to windows 10... I think the issue is that it's being used for a lot of small text boxes. My application presents a grid (Telerik's TreeListView) with text boxes for one of the columns which i want spell checked. I need to be able to provide a custom dictionary to the spell checker; the only way I was able to do this was to subscribe to the textbox loaded event and add the paths in as follows:

        TextBox tb = sender as TextBox;
        tb.ContextMenu = ctx_Spell;
        IList dcts = SpellCheck.GetCustomDictionaries(tb);

        dictsList.Add(dcts);
        if (KMApplication.Settings.UserDictionary != null)
        { dcts.Add(KMApplication.Settings.UserDictionary); }

        foreach (Uri dct in KMApplication.Settings.RevitDictonaries)
        { dcts.Add(dct); }

Granted this calls the add for each and every text box which seems terribly wasteful, but it seemed to be working just fine with little noticeable lag and only on load up. However now on Windows 10 it seems to be a ridiculous lag. On my Windows 8.1 machine I load up a file with a few thousand rows and it appears in about 3 or 4 seconds; on my Windows 10 box, it appears in about 10-15 minutes. If I comment out the custom dictionaries portion of the above code it's back to about 3-4 seconds on either machine.

Does anyone know a better way to do this? Or if there is some way around it in Win10?

Tarpley answered 8/12, 2015 at 22:41 Comment(0)
H
6

Starting .NET 4.6.1 (in Win8.1 & Win10), WPF uses ISpellChecker interface exposed by the OS to implement its SpellChecker, and the performance characteristics could be somewhat different indeed.

Notably, ISpellChecker's custom dictionary registrar acts globally - it no longer acts as a per-control registration. (See KB article link below). As a result, registering the same set of dictionaries over and over for each control is wasteful and can potentially degrade your performance. Besides, the OS will just start ignoring your dictionaries when it reaches an internal limit.

Just register the dictionaries once, or use the alternative registration mechanism outlined at http://blogs.msdn.com/b/wpf/archive/2015/10/29/wpf-in-net-4-6-1.aspx and place the files under %appdata%\microsoft\spelling\.

If you need to run the same application on Win7/Win8 as well as Win8.1/Win10, you may need to detect the OS and branch your dictionary registration strategy.

In general, typical uses of custom dictionaries should continue working as usual - with little difference between .NET 4.6.1 vs previous releases.

Also see https://support.microsoft.com/en-us/kb/3088234 for additional information.

Hidalgo answered 9/12, 2015 at 0:5 Comment(2)
Argh, that's more complicated than I was hoping; looks like I have some research ahead of me :). Thank you for the information and thorough explanation and links to get me started.Tarpley
Do let us know how it goes - esp if you are unable to solve your issue.Hidalgo
F
7

We have experienced a similar issue and saw improved performance by avoiding re-registering custom dictionaries on every TextBox control during load.

Unfortunately, we hit another issue with the way custom dictionaries are handled which can also result in very long loading times if you have even a small number of TextBox controls.

When a WPF application registers a custom dictionary in .NET 4.6.1 on Windows 8.1/10, a temporary dictionary file is created in %localappdata%\Temp and this is registered in the multistring value _GLOBAL_ in the registry key "Computer\HKEY_CURRENT_USER\Software\Microsoft\Spelling\Dictionaries".

If the _GLOBAL_ value ends up referencing a dictionary file which does not exist, the application starts to exhibit very slow loading whenever a control with spell check enabled is initialized.

This can happen by using the "Stop debugging" button in Visual Studio and then running the Disk Clean-up or CCleaner after enough time has passed for these to delete the temp dictionary files.

We managed to fix this by clearing the _GLOBAL_ value of any links to dictionary files which did not exist. The our application began to work as expected.

We raised the following connect bug: https://connect.microsoft.com/VisualStudio/feedback/details/2153484

Flaxman answered 21/12, 2015 at 15:39 Comment(2)
Thanks I will look into that.Tarpley
I think you are my new hero, I wish I could upvote this again. I didn't get this right the first time and still had the issue so I thought it wasn't my issue. However after MUCH debugging and investigation I ended up back around here and did it right this time and it fixed it. THANK YOU!Tarpley
H
6

Starting .NET 4.6.1 (in Win8.1 & Win10), WPF uses ISpellChecker interface exposed by the OS to implement its SpellChecker, and the performance characteristics could be somewhat different indeed.

Notably, ISpellChecker's custom dictionary registrar acts globally - it no longer acts as a per-control registration. (See KB article link below). As a result, registering the same set of dictionaries over and over for each control is wasteful and can potentially degrade your performance. Besides, the OS will just start ignoring your dictionaries when it reaches an internal limit.

Just register the dictionaries once, or use the alternative registration mechanism outlined at http://blogs.msdn.com/b/wpf/archive/2015/10/29/wpf-in-net-4-6-1.aspx and place the files under %appdata%\microsoft\spelling\.

If you need to run the same application on Win7/Win8 as well as Win8.1/Win10, you may need to detect the OS and branch your dictionary registration strategy.

In general, typical uses of custom dictionaries should continue working as usual - with little difference between .NET 4.6.1 vs previous releases.

Also see https://support.microsoft.com/en-us/kb/3088234 for additional information.

Hidalgo answered 9/12, 2015 at 0:5 Comment(2)
Argh, that's more complicated than I was hoping; looks like I have some research ahead of me :). Thank you for the information and thorough explanation and links to get me started.Tarpley
Do let us know how it goes - esp if you are unable to solve your issue.Hidalgo
S
2

Firstly, I want to mention that I know that the post is already a few years old but I think that my answer might help someone out there who has the same problem but where the presented solutions didn't work (like myself).


What fixed it for me was to add the following code to App.config:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Windows.Controls.DoNotAugmentWordBreakingUsingSpeller=true"/>
</runtime>

Alternatively you can also insert the following code after your InitializeComponent() call:

AppContext.SetSwitch(@"Switch.System.Windows.Controls.DoNotAugmentWordBreakingUsingSpeller", true);

Source 1 (XAML solution)
Source 2 (C# solution)

Sturrock answered 10/12, 2020 at 19:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.