在WPF中本地化命令和CultureInfo

时间:2017-06-28 09:03:28

标签: c# wpf xaml

目前,我正在尝试创建在运行时支持语言切换的应用程序。我找到了一个教程,建议使用Resource Dictionaries来实现此目的。建议的方法适用于XAML中具有其内容集的元素,例如,如下<Button Content="{DynamicResource MainTitle}"

问题是我的MenuItem设置为绑定到Header Text的{​​{1}},Command不会改变HeaderCurrentUICulture。它仍然是相同的,或者,我应该说,正确的项目的默认语言,虽然我正在改变语言切换。代表支持的语言的MenuItems也是如此。

这是我正在使用的代码。

App.xaml.cs

public partial class App : Application
{
    private static String prefix = "Resources/lang.";
    public static event EventHandler LanguageChanged;
    private static List<CultureInfo> m_Languages = new List<CultureInfo>();
    public static List<CultureInfo> Languages
    {
        get
        {
            return m_Languages;
        }
    }
    public static CultureInfo Language
    {
        get
        {
            return System.Threading.Thread.CurrentThread.CurrentUICulture;
        }
        set
        {
            if (value == null) throw new ArgumentNullException("value");
            if (value == System.Threading.Thread.CurrentThread.CurrentUICulture) return;

            System.Threading.Thread.CurrentThread.CurrentUICulture = value;
            ResourceDictionary dictionary = new ResourceDictionary();
            dictionary.Source = new Uri(String.Format(prefix+ "{0}.xaml", value.Name), UriKind.Relative);
            ResourceDictionary oldDictionary = (from d in Current.Resources.MergedDictionaries
                                                where d.Source != null &&
                                                d.Source.OriginalString.StartsWith(prefix)
                                                select d).First();

            if (oldDictionary != null)
            {
                int index = Current.Resources.MergedDictionaries.IndexOf(oldDictionary);
                Current.Resources.MergedDictionaries.Remove(oldDictionary);
                Current.Resources.MergedDictionaries.Insert(index, dictionary);
            }
            else
            {
                Current.Resources.MergedDictionaries.Add(dictionary);
            }
            LanguageChanged(Current, new EventArgs());
        }
    } 
    public App()
    {
        InitializeComponent();
        App.LanguageChanged += App_LanguageChanged;
        m_Languages.Clear();
        m_Languages.Add(new CultureInfo("en"));
        m_Languages.Add(new CultureInfo("ru-RU"));
        Language = WpfTestProject.Properties.Settings.Default.DefaultLanguage;
    }
    public void App_LanguageChanged(Object sender, EventArgs e)
    {
        WpfTestProject.Properties.Settings.Default.DefaultLanguage = Language;
        WpfTestProject.Properties.Settings.Default.Save();
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        App.LanguageChanged += LanguageChanged;
        SetLanguageMenu();
    }

    private void SetLanguageMenu()
    {
        CultureInfo currLang = App.Language;
        LangMenu.Items.Clear();
        foreach (var lang in App.Languages)
        {
            MenuItem menuLang = new MenuItem();
            Debug.WriteLine("Here is a display name: " + lang.DisplayName);
            menuLang.Header = lang.DisplayName;
            menuLang.Tag = lang;
            menuLang.IsChecked = lang.Equals(currLang);
            menuLang.Click += ChangeLanguageClick;
            LangMenu.Items.Add(menuLang);
        }
    }
    private void LanguageChanged(Object sender, EventArgs e)
    {
        //I've tried resseting LanguageMenu from here - no effect
        CultureInfo currLang = App.Language;
        foreach (MenuItem i in LangMenu.Items)
        {
            CultureInfo ci = i.Tag as CultureInfo;
            i.IsChecked = ci != null && ci.Equals(currLang);
        }
    }
    private void ChangeLanguageClick(Object sender, EventArgs e)
    {
        MenuItem mi = sender as MenuItem;
        if (mi != null)
        {
            CultureInfo lang = mi.Tag as CultureInfo;
            if (lang != null)
            {
                App.Language = lang;
                SetLanguageMenu();
            }
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfTestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfTestProject"
    mc:Ignorable="d"
    Title="{DynamicResource MainTitle}" Height="600" Width="800">
<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed"/>
    <CommandBinding Command="ApplicationCommands.Open" Executed="OpenCommand_Executed"/>
    <CommandBinding Command="ApplicationCommands.Save" Executed="SaveCommand_Executed"/>
    <CommandBinding Command="ApplicationCommands.SaveAs" Executed="SaveAsCommand_Executed"/>
</Window.CommandBindings>
<Window.InputBindings>
    <KeyBinding Key="N" Modifiers="Ctrl" Command="{Binding ApplicationCommands.New}"/>
    <KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding ApplicationCommands.Open}"/>
    <KeyBinding Key="S" Modifiers="Ctrl" Command="{Binding ApplicationCommands.Save}"/>
    <KeyBinding Key="S" Modifiers="Ctrl+Shift" Command="{Binding ApplicationCommands.SaveAs}"/>
</Window.InputBindings>
    <DockPanel Name="DockPanel" HorizontalAlignment="Stretch" LastChildFill="False" VerticalAlignment="Stretch">
        <MenuItem Command="ApplicationCommands.Open" Header="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Command.Text}"/>
        <MenuItem Name="LangMenu" Header="Languages" HorizontalAlignment="Right"/>
    </DockPanel>
</Window>

更新

英语资源字典

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfTestProject.Properties"
                xmlns:v="clr-namespace:System;assembly=mscorlib">
<v:String x:Key="MainTitle">Title</v:String>

的App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
    <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="WpfTestProject.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
    </sectionGroup>
</configSections>
<startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<userSettings>
    <WpfTestProject.Properties.Settings>
        <setting name="DefaultLanguage" serializeAs="String">
            <value>en</value>
        </setting>
    </WpfTestProject.Properties.Settings>
</userSettings>

关于我做错了什么的任何想法?

1 个答案:

答案 0 :(得分:1)

  

问题是我的MenuItem,它的标题设置为绑定到它的文本命令,不会根据CurrentUICulture更改标题。

当然不是,为什么会这样?

您应该像设置其他元素的本地化文本一样设置Header的{​​{1}}:

MenuItem

显然,您必须执行此操作才能使本地化工作在<MenuItem Command="ApplicationCommands.Open" Header="{DynamicResource OpenText}"/> 元素之间。