Конфликтующие языковые настройки WPF richtextbox

На компьютере с культурой. Установка "de-DE" (или любой другой, чем "en-US" ), я хотел бы иметь RichTextBox с включенной проверкой орфографии, при этом установленный язык установлен на английском ( "en-US" ).

<RichTextBox SpellCheck.IsEnabled="True" Language="en-US"/>

Это позволяет проверить орфографию, но проверяет с культурой "de-DE" , а не "en-US" . То же самое имеет место при добавлении xml:lang="en-us".

Однако

<RichTextBox SpellCheck.IsEnabled="True" InputLanguageManager.InputLanguage="en-US"/>

правильно разрешает проверку орфографии на английском языке, но также изменяет раскладку клавиатуры на "en-US" .

Как я могу установить системную клавиатуру (в моем случае "de-DE" ), но проверка орфографии RichTextBox на английском?

(Потенциально релевантно: я использую .NET Framework 4.5)

Ответ 1

Я попытался воспроизвести вашу проблему, и для меня я не мог активировать проверку орфографии на другом языке, кроме английского, хотя я изменил региональные настройки и культуру Thread до того, как компоненты были инициализированы:

    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("de-DE");
    Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("de-DE");

На основе решения, предоставленного здесь, я смог заставить его работать:

1) Наследовать от RichTextBox:

class RichTextBoxEx : RichTextBox
{
    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        var changeList = e.Changes.ToList();
        if (changeList.Count > 0)
        {
            foreach (var change in changeList)
            {
                TextPointer start = null;
                TextPointer end = null;
                if (change.AddedLength > 0)
                {
                    start = this.Document.ContentStart.GetPositionAtOffset(change.Offset);
                    end = this.Document.ContentStart.GetPositionAtOffset(change.Offset + change.AddedLength);
                }
                else
                {
                    int startOffset = Math.Max(change.Offset - change.RemovedLength, 0);
                    start = this.Document.ContentStart.GetPositionAtOffset(startOffset);
                    end = this.Document.ContentStart.GetPositionAtOffset(change.Offset);
                }

                if (start != null && end != null)
                {
                    var range = new TextRange(start, end);
                    range.ApplyPropertyValue(FrameworkElement.LanguageProperty, Document.Language);
                }
            }
        }
        base.OnTextChanged(e);
    }
}

2) Используйте его в своем xaml

<local:RichTextBoxEx x:Name="richTextBox" HorizontalAlignment="Left" Height="100" Margin="33,100,0,0" VerticalAlignment="Top" Width="474" 
             xml:lang="de-DE" SpellCheck.IsEnabled="True">

[править]

Я также пытался избежать применения значения свойства для каждого изменения текста, определяя таймер и проверку орфографии все время от времени. На моем компьютере я не вижу разницы при использовании самого длинного содержимого статьи в Википедии:

class RichTextBoxEx : RichTextBox
{
    DispatcherTimer timer;
    bool textChanged = false;

    public RichTextBoxEx()
    {
        if (DesignerProperties.GetIsInDesignMode(this))
            return;

        timer = new DispatcherTimer();
        timer.Interval = new TimeSpan(0, 0, 1);
        timer.Tick += timer_Tick;
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        try
        {
            var range = new TextRange(Document.ContentStart, Document.ContentEnd);
            range.ApplyPropertyValue(FrameworkElement.LanguageProperty, Document.Language);
        }
        finally
        {
            textChanged = false;
        }
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        // TODO: remove if timer version works correctly
        //var changeList = e.Changes.ToList();
        //if (changeList.Count > 0)
        //{
        //    foreach (var change in changeList)
        //    {
        //        TextPointer start = null;
        //        TextPointer end = null;
        //        if (change.AddedLength > 0)
        //        {
        //            start = this.Document.ContentStart.GetPositionAtOffset(change.Offset);
        //            end = this.Document.ContentStart.GetPositionAtOffset(change.Offset + change.AddedLength);
        //        }
        //        else
        //        {
        //            int startOffset = Math.Max(change.Offset - change.RemovedLength, 0);
        //            start = this.Document.ContentStart.GetPositionAtOffset(startOffset);
        //            end = this.Document.ContentStart.GetPositionAtOffset(change.Offset);
        //        }

        //        if (start != null && end != null)
        //        {
        //            var range = new TextRange(start, end);
        //            range.ApplyPropertyValue(FrameworkElement.LanguageProperty, Document.Language);
        //        }
        //    }
        //}

        textChanged = true;
        base.OnTextChanged(e);
    }
}