【问题标题】:Load custom dictionary just once. Wpf spellchecker只加载一次自定义字典。 Wpf 拼写检查器
【发布时间】:2014-08-22 01:13:03
【问题描述】:

所以,这里是代码:

IList dictionaries = SpellCheck.GetCustomDictionaries(tb);
Uri uri = new Uri("Russian.lex", UriKind.Relative);
dictionaries.Add(uri);
tb.SpellCheck.IsEnabled = true;

问题是,我必须使用拼写检查创建多个文本框,而分配自定义词典的唯一方法是将 Uri 传递给 TextBoxBase.CustomDictionaries.Add()。所以每次我设置 SpellCheck.IsEnabled 时都会有 3-5 秒的延迟,我认为这是从硬盘加载文件造成的。最重要的是,似乎每次加载字典时,它都会永久保留在内存中。

关于如何加载自定义字典一次而不是重复使用它的任何提示?

【问题讨论】:

  • static class?首次使用时加载的实用程序类?
  • SpellCheckSpellCheck.CustomDictionaries 是只读属性。尝试使用 XamlWriter 克隆带有已加载字典的 static TextBox 也会失败,字典会丢失。恕我直言,请您在回答之前尝试研究问题吗?
  • 恕我直言,请您在回答之前尝试研究问题?...首先,这表明没有尊重。其次,@crashmstr 已花时间在他们的评论中为您提供建议……这不是答案,因此他们试图回答您的问题。第三,他们没有暗示你认为他们是什么,所以你编造了你自己​​的答案并指责他们没有奏效。这是一个非常糟糕的节目,尤其是来自这个网站的这样一个初级成员。
  • 我的错,我认为建议是一个答案。我的道歉
  • 请注意,在 .net 4.6 及更高版本中不需要此解决方案。应用于 .net 4.6 中任何文本框的字典会自动应用于每个文本框和富文本框。

标签: wpf dictionary spell-checking


【解决方案1】:

您可以创建一个包含自定义 lex 词典的临时文件。

以这种方式实现它,其中FileSystemHelper 只是一个辅助类,但它只是使用PathDirectories 类来创建一个File

public Uri CreateCustomLexiconDictionary()
{
 if (!_fileSystemHelper.Exists(_customDictionaryLocation))
 {
   _fileSystemHelper.AppendLine(_customDictionaryLocation, @"Line");
  }
  if ((_fileSystemHelper.Exists(_customDictionaryLocation) && customDictionaries.Count == 0))
                return new Uri("file:///" + _customDictionaryLocation);
  }
 }

您使用的每个TextBoxes 都可以从那里调用CreateCustomLexiconDictionary,然后将其添加到SpellCheckDictionaries 对象中

IList dictionaries = SpellCheck.GetCustomDictionaries(tb);
dictionaries.Add(CreateCustomLexiconDictionary());

完成后,您可以将URI 删除到字典中,以便清理它。完成后也删除文件。

另外,RichTextBox SpellCheck 确实很慢,Microsoft 也意识到了这一点。

【讨论】:

    【解决方案2】:

    在许多错误的开始之后,我想我已经成功了。

    我四处寻找,直到找到自定义字典的内部表示(ILexicon)。然后我将这个 Ilexicon 分配给每个新的文本内容。这些接口都不是公开的,因此我冒着在未来版本甚至服务包中被破坏的明显风险,但它适用于今天。 [这在 .net 4.6 中中断并变得不必要,见下文。]

    using System;
    using System.Collections;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using Melville.Library.ReflectionHelpers;
    
    namespace PhotoDoc.Wpf.Controls.FormControls
    {
      public static class DynamicDictionaryLoader
      {
        private static string dictionaryLocation;
        public static string DictionaryLocation
        {
          get
          {
            if (dictionaryLocation == null)
            {
              var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
              dictionaryLocation = Path.Combine(path, "UsMedicalEnglish.dic");
            }
            return dictionaryLocation;
          }
        }
    
        public static void AddDictionary(TextBoxBase targetControl)
        {
          try
          {
            InnerLoadDictionary(targetControl);
          }
          catch (UriFormatException)
          {
            // occasionaly occurrs in odd instalations.  You just don't get the medical dictionary
          }
          catch (ArgumentException)
          {
            // this is a rare bug that I think may be a race condition inside WPF.  I've only triggered it 2-3 times.
            // One time was when I had seven files open at once.  The other, ironically, was when activating the
            // default text for a field.  
    
            // In this rare error exception, you will just get all your medical words flagged as mispellings for that
            // textbox.  I won't know for a while if this worked, because I only saw the bug after months of daily use
            // of the program.
          }
        }
    
        private static object oldDictionary = null;
        private static object dictionaryLoaderLock = new Object();
    
        private static void InnerLoadDictionary(TextBoxBase targetControl)
        {
          var dictionary = SpellCheck.GetCustomDictionaries(targetControl);
          if (dictionary.Count < 1)
          {
              var speller = dictionary.GetProperty("Speller");
              var uriMap = speller.GetProperty("UriMap") as IDictionary;
              if (uriMap.Count > 0) return; // already initalized
              lock (dictionaryLoaderLock)
              {
                var dictionaryUri = new Uri(DictionaryLocation, UriKind.Absolute);
                if (oldDictionary == null)
                {
                  dictionary.Add(dictionaryUri);
                  oldDictionary = uriMap.Values.OfType<object>().FirstOrDefault();
                }
                else
                {
                  if (!(bool) speller.Call("EnsureInitialized")) return;
                  uriMap.Add(dictionaryUri, oldDictionary);
                  GetContext(
                    speller.GetField("_spellerInterop").
                      GetField("_textChunk") as ITextChunk).
                      AddLexicon(oldDictionary.GetProperty("Lexicon") as ILexicon);
                  speller.Call("ResetErrors");
                }
              }
          }
        }
    
        private static ITextContext GetContext(ITextChunk chunk)
        {
          ITextContext ret = null;
          chunk.get_Context(out ret);
          return ret;
        }
    
        #region Com Imports
        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("549F997E-0EC3-43d4-B443-2BF8021010CF")]
        private interface ITextChunk
        {
          void stub_get_InputText();
          void stub_put_InputText();
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void SetInputArray([In] IntPtr inputArray, Int32 size);
          void stub_RegisterEngine();
          void stub_UnregisterEngine();
          void stub_get_InputArray();
          void stub_get_InputArrayRange();
          void stub_put_InputArrayRange();
          void get_Count(out Int32 val);
          void get_Item(Int32 index, [MarshalAs(UnmanagedType.Interface)] out object val);
          void stub_get__NewEnum();
          [SecurityCritical]
          void get_Sentences([MarshalAs(UnmanagedType.Interface)] out object val);
          void stub_get_PropertyCount();
          void stub_get_Property();
          void stub_put_Property();
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void get_Context([MarshalAs(UnmanagedType.Interface)] out ITextContext val);
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void put_Context([MarshalAs(UnmanagedType.Interface)] ITextContext val);
          void stub_get_Locale();
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void put_Locale(Int32 val);
          void stub_get_IsLocaleReliable();
          void stub_put_IsLocaleReliable();
          void stub_get_IsEndOfDocument();
          void stub_put_IsEndOfDocument();
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void GetEnumerator([MarshalAs(UnmanagedType.Interface)] out object val);
          void stub_ToString();
          void stub_ProcessStream();
          void get_ReuseObjects(out bool val);
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void put_ReuseObjects(bool val);
        }
    
        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("B6797CC0-11AE-4047-A438-26C0C916EB8D")]
        private interface ITextContext
        {
          void stub_get_PropertyCount();
          void stub_get_Property();
          void stub_put_Property();
          void stub_get_DefaultDialectCount();
          void stub_get_DefaultDialect();
          void stub_AddDefaultDialect();
          void stub_RemoveDefaultDialect();
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void get_LexiconCount([MarshalAs(UnmanagedType.I4)] out Int32 lexiconCount);
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void get_Lexicon(Int32 index, [MarshalAs(UnmanagedType.Interface)] out ILexicon lexicon);
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void AddLexicon([In, MarshalAs(UnmanagedType.Interface)] ILexicon lexicon);
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void RemoveLexicon([In, MarshalAs(UnmanagedType.Interface)] ILexicon lexicon);
          void stub_get_Version();
          void stub_get_ResourceLoader();
          void stub_put_ResourceLoader();
          [SecurityCritical, SuppressUnmanagedCodeSecurity]
          void get_Options([MarshalAs(UnmanagedType.Interface)] out object val);
          void get_Capabilities(Int32 locale, [MarshalAs(UnmanagedType.Interface)] out object val);
          void stub_get_Lexicons();
          void stub_put_Lexicons();
          void stub_get_MaxSentences();
          void stub_put_MaxSentences();
          void stub_get_IsSingleLanguage();
          void stub_put_IsSingleLanguage();
          void stub_get_IsSimpleWordBreaking();
          void stub_put_IsSimpleWordBreaking();
          void stub_get_UseRelativeTimes();
          void stub_put_UseRelativeTimes();
          void stub_get_IgnorePunctuation();
          void stub_put_IgnorePunctuation();
          void stub_get_IsCaching();
          void stub_put_IsCaching();
          void stub_get_IsShowingGaps();
          void stub_put_IsShowingGaps();
          void stub_get_IsShowingCharacterNormalizations();
          void stub_put_IsShowingCharacterNormalizations();
          void stub_get_IsShowingWordNormalizations();
          void stub_put_IsShowingWordNormalizations();
          void stub_get_IsComputingCompounds();
          void stub_put_IsComputingCompounds();
          void stub_get_IsComputingInflections();
          void stub_put_IsComputingInflections();
          void stub_get_IsComputingLemmas();
          void stub_put_IsComputingLemmas();
          void stub_get_IsComputingExpansions();
          void stub_put_IsComputingExpansions();
          void stub_get_IsComputingBases();
          void stub_put_IsComputingBases();
          void stub_get_IsComputingPartOfSpeechTags();
          void stub_put_IsComputingPartOfSpeechTags();
          void stub_get_IsFindingDefinitions();
          void stub_put_IsFindingDefinitions();
          void stub_get_IsFindingDateTimeMeasures();
          void stub_put_IsFindingDateTimeMeasures();
          void stub_get_IsFindingPersons();
          void stub_put_IsFindingPersons();
          void stub_get_IsFindingLocations();
          void stub_put_IsFindingLocations();
          void stub_get_IsFindingOrganizations();
          void stub_put_IsFindingOrganizations();
          void stub_get_IsFindingPhrases();
          void stub_put_IsFindingPhrases();
        }
    
        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("004CD7E2-8B63-4ef9-8D46-080CDBBE47AF")]
        internal interface ILexicon
        {
          void ReadFrom([MarshalAs(UnmanagedType.BStr)]string fileName);
          void stub_WriteTo();
          void stub_GetEnumerator();
          void stub_IndexOf();
          void stub_TagFor();
          void stub_ContainsPrefix();
          void stub_Add();
          void stub_Remove();
          void stub_Version();
          void stub_Count();
          void stub__NewEnum();
          void stub_get_Item();
          void stub_set_Item();
          void stub_get_ItemByName();
          void stub_set_ItemByName();
          void stub_get0_PropertyCount();
          void stub_get1_Property();
          void stub_set_Property();
          void stub_get_IsReadOnly();
        }
        #endregion
      }
    }
    

    这段代码依赖于我的反射助手类:

    using System;
    using System.Linq;
    using System.Reflection;
    
    namespace Melville.Library.ReflectionHelpers
    {
      public static class ReflectionHelper
      {
        public static void SetField(this object target, string property, object value)
        {
          Field(target, property).SetValue(target, value);
        }
    
        public static object GetField(this object target, string name)
        {
          return Field(target, name).GetValue(target);
        }
    
        private static FieldInfo Field(object target, string name)
        {
          return target.GetType().GetField(name, 
            BindingFlags.NonPublic | BindingFlags.Public |BindingFlags.GetField|
            BindingFlags.FlattenHierarchy|BindingFlags.Instance);
        }
    
        public static object GetProperty(this object target, string name)
        {
          return Property(target, name).
            GetValue(target);
        }
    
        private static PropertyInfo Property(object target, string name)
        {
          return target.GetType().GetProperty(name, 
            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetProperty|BindingFlags.FlattenHierarchy|BindingFlags.Instance);
        }
    
        public static void SetProperty(this object target, string property, object value)
        {
          Property(target, property).SetValue(target, value);
        }
    
        private const BindingFlags MethodBindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy | BindingFlags.Instance;
    
        private static MethodInfo Method(object target, string name, Type[] types)
        {
          return target.GetType().GetMethod(name,
            MethodBindingFlags, null, CallingConventions.Any, types, null) ;
        }
    
        public static MethodInfo Method(object target, string name)
        {
          var methodInfos = target.GetType().GetMethods(MethodBindingFlags);
          return methodInfos.FirstOrDefault(i=>i.Name.Equals(name, StringComparison.Ordinal));
        }
    
        public static object Call(this object target, string methodName, params object[] paramenters)
        {
          return Method(target, methodName, paramenters.Select(i => i.GetType()).ToArray()).Invoke(target, paramenters);
        }
      }
    }
    

    【讨论】:

    • 嗨,约翰!感谢分享解决方案。可悲的是,我没有时间检查它是否有效,而且问题对我来说早已消失,因为我们使用的是 devexpress 控件,并且他们提供了将他们的拼写检查器与原生 wpf 文本框一起使用的能力。我会将您的帖子标记为答案。希望它会帮助某人
    • 请注意,在 .net 4.6 及更高版本中不需要此解决方案。应用于 .net 4.6 中任何文本框的字典会自动应用于每个文本框和富文本框。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多