WPF 拼写检查未在选项卡中加载自定义词典

WPF spell checking not loading a custom dictionary in a tab

如果我在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);
}

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

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

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

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

有谁知道让自定义词典适用于 window 首次加载时不可见的文本框的方法吗?

谢谢

P.S。这是辅助方法的代码,它使用链接的 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);
    }
  }
}

可能有更好的解决方案,但您可以使用 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.
    }
}

虽然 Dean Kuga 的回答看起来很有希望,但它对我不起作用。经过更多搜索后,似乎存在一个错误,在大多数情况下会阻止 Loaded 事件被触发。在对解决该问题的 SO question where I saw this mentioned, Marcin Wisnicki linked to 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"改成了"Initialised",除此之外,DP代码是一样的

希望这对某人有所帮助。