【问题标题】:WPF spell checking not loading a custom dictionary in a tabWPF拼写检查未在选项卡中加载自定义字典
【发布时间】:2018-05-23 01:18:05
【问题描述】:

如果我在 App.xaml 中全局启用拼写检查...

<Application.Resources>
  <Style TargetType="TextBox">
    <Setter Property="SpellCheck.IsEnabled"
            Value="True" />
  </Style>
</Application.Resources>

...然后我会在应用程序中的所有文本框中得到红色下划线和拼写检查,无论它们在哪里。

如果我想添加自定义字典,那么我必须使用类似于this SO answer中显示的代码,然后调用它如下...

public MainWindow() {
  InitializeComponent();
  Loaded += (_, __) => Helpers.SetCustomDictionary(this);
}

(帮助方法的代码显示在下方)

这适用于窗口首次加载时显示的文本框,但如果我有一个选项卡控件,并且默认选项卡有一个文本框,则不会应用自定义字典。

我尝试在选项卡加载时调用Helpers.SetCustomDictionary(this),但这也不起作用。我可以看到在窗口加载时调用了该方法,我的猜测是在那个阶段,选项卡的内容还没有创建,所以该方法没有找到它们来设置自定义字典。

我发现唯一有效的方法是在加载单个文本框本身时调用它。但是,这很痛苦,因为我必须为每个文本框单独执行此操作。

有谁知道如何让自定义字典适用于在窗口首次加载时不可见的文本框?

谢谢

附:这是辅助方法的代码,它使用链接的 SO 回复中显示的 FindAllChildren() 方法...

public static void SetCustomDictionary(DependencyObject parent) {
  Uri uri = new Uri("pack://application:,,,/CustomDictionary.lex");
  List<TextBox> textBoxes = new List<TextBox>();
  FindAllChildren(parent, ref textBoxes);
  foreach (TextBox tb in textBoxes) {
    if (tb.SpellCheck.IsEnabled && !tb.SpellCheck.CustomDictionaries.Contains(uri)) {
      tb.SpellCheck.CustomDictionaries.Add(uri);
    }
  }
}

【问题讨论】:

    标签: wpf spell-checking


    【解决方案1】:

    可能有更好的解决方案,但您可以使用 App.xaml.cs 的 OnStartup 事件在使用单个事件处理程序加载每个 TextBox 时为其设置字典:

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
                base.OnStartup(e);
                EventManager.RegisterClassHandler(typeof(TextBox), FrameworkElement.LoadedEvent, new RoutedEventHandler(TextBox_OnLoaded));
        }
    
        private void TextBox_OnLoaded(object sender, RoutedEventArgs e)
        {
                // Set custom dictionary here.
        }
    }
    

    【讨论】:

    • 感谢您的回复,但从未调用过 TextBox_OnLoaded 方法。在尝试调试时,我将TextBox3.Loaded += (_, __) =&gt; Debug.WriteLine("TextBox3.Loaded"); 添加到主窗口的ctor,然后为TextBox3 设置了自定义字典。你能理解这个吗?我真的不想在每个文本框的 Loaded 事件中添加一个虚拟 cal,而是违背了目的。再次感谢。
    • 我试过了,它确实奏效了,但我并没有比刚开始时好多少。正如我在最初的问题中所说,我试图找到一种方法来避免必须为每个文本框单独执行此操作。不管怎么说,还是要谢谢你。还有其他想法吗?
    • 当所有文本框都有一个事件处理程序时,每个文本框的情况如何?
    • 抱歉,误读了您的评论。我以为你的意思是为每个文本框的加载事件单独添加一个钩子。我刚刚重读了您的评论并意识到您的意思。但是,它没有任何区别,即使您进行了更改,也不会为任何文本框加载自定义字典,无论是否可见。
    • 只是补充一下,我尝试对其他控件执行相同的调用EventManager.RegisterClassHandler,并且从未调用过事件处理程序,因此它不是特定于文本框的。我还尝试在窗口 ctor 中使用该行(而不是在 App.xaml.cs 中),并且从未调用过事件处理程序。似乎这个问题与拼写检查器等无关,这纯粹是事件处理程序没有被调用的问题。有任何想法吗?再次感谢。
    【解决方案2】:

    虽然 Dean Kuga 的回答看起来很有希望,但它对我不起作用。经过一番搜索后,似乎有一个错误会阻止Loaded 事件在大多数情况下被触发。在对SO question where I saw this mentioned 答案的评论中,Marcin Wisnicki 链接到了解决该问题的some code he wrote

    因为我只希望它适用于文本框,所以我稍微简化了他的代码。如果它可以帮助任何人,这是我的简化代码...

    public partial class App {
      protected override void OnStartup(StartupEventArgs e) {
        base.OnStartup(e);
        EventManager.RegisterClassHandler(typeof(Window),
          FrameworkElement.SizeChangedEvent, new RoutedEventHandler(OnSizeChanged));
        EventManager.RegisterClassHandler(typeof(TextBox),
          FrameworkElement.LoadedEvent, new RoutedEventHandler(OnLoaded), true);
      }
    
      private static void OnSizeChanged(object sender, RoutedEventArgs e) {
        SetMyInitialised((Window)sender, true);
      }
    
      private static void OnLoaded(object sender, RoutedEventArgs e) {
        if (e.OriginalSource is TextBox) {
          TextBox tb = (TextBox)e.OriginalSource;
          Helpers.SetCustomDictionaryTextBox(tb);
        }
      }
    
      #region MyInitialised dependency property
    
      public static readonly DependencyProperty MyInitialisedProperty =
        DependencyProperty.RegisterAttached("MyInitialised",
          typeof(bool),
          typeof(App),
          new FrameworkPropertyMetadata(false,
            FrameworkPropertyMetadataOptions.Inherits,
            OnMyInitialisedChanged));
    
      private static void OnMyInitialisedChanged(DependencyObject dpo,
        DependencyPropertyChangedEventArgs ev) {
        if ((bool)ev.NewValue && dpo is FrameworkElement) {
          (dpo as FrameworkElement).Loaded += delegate { };
        }
      }
    
      public static void SetMyInitialised(UIElement element, bool value) {
        element.SetValue(MyInitialisedProperty, value);
      }
    
      public static bool GetMyInitialised(UIElement element) {
        return (bool)element.GetValue(MyInitialisedProperty);
      }
    
      #endregion MyInitialised
    }
    

    作为英文,我将“Initialized”改为“Initialized”,但除此之外,DP代码相同。

    希望这对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 2014-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多