简体   繁体   中英

How to apply cultureinfo (language) property to WPF richtextbox selection

I usually can find solutions somewhere on the web, and mostly here at SO. I have tried for two days now to resolve this issue with all attempts yielding the very same results. Hopefully someone here can provide the help I need.

I have not added any code for languages anywhere in the app except in the combobox where users can select the language and the dropdown event when they select the language seen below following the definition of the rtb.

below is the xaml definition of the richtextbox

            <RichTextBox Name="rtbDoc" IsDocumentEnabled="true" Padding="4"
                     MinHeight="350" HorizontalAlignment="Stretch"
                     VerticalAlignment="Stretch" SpellCheck.IsEnabled="True" VerticalScrollBarVisibility="Auto"
                     HorizontalScrollBarVisibility="Auto" AcceptsTab="True" IsTabStop="False"  
                     IsVisibleChanged="rtbDoc_IsVisibleChanged" 
                     KeyUp="rtbDoc_KeyUp" PreviewMouseUp="rtbDoc_MouseUp" PreviewMouseDown="rtbDoc_PreviewMouseDown"
                     PreviewKeyDown="rtbDocPreviewKeyDown"
                     ContextMenuOpening="rtb_ContextMenuOpening" 
                     ToolTip="Edit documents" Width="941"  >

Below is the code in the event where the language should be applied, but only changes the spellchecker, not only for the selected text but for the entire document.

               private void cbbLanguage_DropDownClosed(object sender, EventArgs e)
    {
        if (this.cbbLanguage.SelectedIndex < 0) { return; }

        int iLcid = (int)this.cbbLanguage.SelectedValue;
        _ci = new System.Globalization.CultureInfo(iLcid);

        // following does not seem to have any desire affect
        //System.Threading.Thread.CurrentThread.CurrentCulture = _ci;
        //System.Threading.Thread.CurrentThread.CurrentUICulture = _ci;
        //CultureInfo ci2 = CultureInfo.CreateSpecificCulture(_ci.Name);

        // both of following changes only spellchecker for document so that all English text underlined
        //InputLanguageManager.SetInputLanguage(this.rtbDoc, CultureInfo.CreateSpecificCulture(ci2.Name));
        //XmlLanguage xl = this.rtbDoc.Document.Language;

        int iIdx = this.cbbLanguage.SelectedIndex;
        DataRowView drv = this.cbbLanguage.SelectedItem as DataRowView;
        DataRow[] dr = _dtLanguages.Select("LanguageId = " + drv[0].ToString());  // number id of language selected

        XmlLanguage xl2 = XmlLanguage.GetLanguage(dr[0]["LanguageName"].ToString());

        // this works in changing the property and all words in document 
        //  become underlined indicating spellchecker changed but text remained English
        //this.rtbDoc.Language = xl2;  

        if (this.rtbDoc.Selection.Text.Length > 1)
        {
            // this works to immediately (no focus change necessary) to 
            //   change the property and the spellchecker shows the entire 
            //   doc content misspelled, but the selected text remains english
            this.rtbDoc.Selection.ApplyPropertyValue(FrameworkElement.LanguageProperty, xl2);  
        }

    }

After getting help from Mr. Shloime Rosenblum I have modified my code and posting here for others who might be seeking the same solution. First, changing the existing text in a selection is not possible. The better solution is to allow the user to switch languages while typing. The following code enables this to be done smoothly and immediately.

First build the list for the ComoboBox. I choose using a table rather than a list with a class because for me this more intuitive and simpler.

private void LoadLanguages()
    {
        CultureInfo[] ciCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);

        // create table
        _dtLanguages = new DataTable();
        _dtLanguages.Columns.Add("LanguageId", typeof(int));
        _dtLanguages.Columns.Add("LanguageName", typeof(string));
        _dtLanguages.Columns.Add("LanguageDisplayName", typeof(string));

        // populate table
        foreach ( CultureInfo ci in ciCultures)
        {
            DataRow dr = _dtLanguages.NewRow();
            dr["LanguageId"] = ci.LCID;
            dr["LanguageName"] = ci.Name;
            dr["LanguageDisplayName"] = ci.DisplayName + "(" + ci.NativeName + ")";
            _dtLanguages.Rows.Add(dr);
        }

        try
        {
            _dtLanguages.DefaultView.Sort = "LanguageDisplayName ASC";
            this.cbbLanguage.ItemsSource = _dtLanguages.DefaultView;
            this.cbbLanguage.DisplayMemberPath = "LanguageDisplayName";
            this.cbbLanguage.SelectedValuePath = "LanguageId";
        }
        catch (Exception ex)
        {
            int i = ex.Message.Length;
        }

        return;
    }

Then add the selectionchanged event for user selecting a language.

        private void cbbLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count == 0) { return; }

        // set language for rtb
        DataRowView drv = e.AddedItems[0] as DataRowView;
        DataRow[] dr = _dtLanguages.Select("LanguageId = " + drv[0].ToString());  // number id of language selected
        XmlLanguage xl2 = XmlLanguage.GetLanguage(dr[0]["LanguageName"].ToString());
        this.rtbDoc.Language = xl2;

        // set keyboard to match language setting; language must exactly match 
        // a keyboard defined in Windows.Control Panel.Language.Keyboards

        int iLcid = (int)this.cbbLanguage.SelectedValue;
        CultureInfo ci = new System.Globalization.CultureInfo(iLcid);
        InputLanguageManager.Current.CurrentInputLanguage = CultureInfo.CreateSpecificCulture(ci.Name);

        // rtb applies changes when receiving focus
        this.rtbDoc.Focus();
    }

The user selects the language and begins typing in the new language until he selects another. No changes necessary to the rtb's xaml code and no events necessary for rtb focus changes.

You can do with the GotFocus and LostFocus events from rtbDoc and changing the InputLanguageManager .

<RichTextBox Name="rtbDoc" IsDocumentEnabled="true" Padding="4"
                 GotFocus="ChangeLanguage"
                 LostFocus="ChangeToDefault"
                 MinHeight="350" HorizontalAlignment="Stretch"
                 VerticalAlignment="Stretch" SpellCheck.IsEnabled="True" VerticalScrollBarVisibility="Auto"
                 HorizontalScrollBarVisibility="Auto" AcceptsTab="True" IsTabStop="False"  
                 IsVisibleChanged="rtbDoc_IsVisibleChanged" 
                 KeyUp="rtbDoc_KeyUp" PreviewMouseUp="rtbDoc_MouseUp" PreviewMouseDown="rtbDoc_PreviewMouseDown"
                 PreviewKeyDown="rtbDocPreviewKeyDown"
                 ContextMenuOpening="rtb_ContextMenuOpening" 
                 ToolTip="Edit documents" Width="941"  >

and in code

public CultureInfo defaultLanguage;
public CultureInfo ci;
private void cbbLanguage_DropDownClosed(object sender, EventArgs e)
{

    int iLcid = Int32.Parse(_lstLanguages[this.cbbLanguage.SelectedIndex].LanguageId);
    ci = new System.Globalization.CultureInfo(iLcid);
    System.Threading.Thread.CurrentThread.CurrentCulture = ci;
    System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
    CultureInfo ci2 = CultureInfo.CreateSpecificCulture(ci.Name);

    //InputLanguageManager.SetInputLanguage(this.rtbDoc, CultureInfo.CreateSpecificCulture(ci2.Name));
    XmlLanguage xl = this.rtbDoc.Document.Language;
    XmlLanguage xl2 = XmlLanguage.GetLanguage(ci2.IetfLanguageTag);

    // this works in changing the property but nothing changes in the doc
    this.rtbDoc.Language = xl2;  

    if (this.rtbDoc.Selection.Text.Length > 1)
    {
        // this works to change the property and the spellchecker shows the entire 
        // doc content misspelled, but the selected text remains english
        this.rtbDoc.Selection.ApplyPropertyValue(FrameworkElement.LanguageProperty, xl2);  
    }

}

private void ChangeLanguage(object sender, RoutedEventArgs e)
    {
        defaultLanguage = InputLanguageManager.Current.CurrentInputLanguage;
        InputLanguageManager.Current.CurrentInputLanguage = CultureInfo.CreateSpecificCulture(ci.Name);

    }

private void ChangeToDefault(object sender, RoutedEventArgs e)
    {
        InputLanguageManager.Current.CurrentInputLanguage = defaultLanguage;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM