如何在 运行 时间使用资源字典更改 UI 语言?

How to change UI language using resource dictionary at run time?

我想通过 button_click 事件更改我的项目语言,所以我使用 ResourceDictionary 来这样做:

XAML

    <Button Content="{DynamicResource LanguageSetting}" Click="btn_LanguageSetting_Click"/>

代码隐藏

    public static string windowCurrentLanguageFile = "Language/en.xaml";
    private void btn_LanguageSetting_Click(object sender, RoutedEventArgs e)
    {
        windowCurrentLanguageFile = windowCurrentLanguageFile == "Language/en.xaml"
            ? "Language/fr.xaml"
            : "Language/en.xaml";

        var rd = new ResourceDictionary() { Source = new Uri(windowCurrentLanguageFile, UriKind.RelativeOrAbsolute) };

        if (this.Resources.MergedDictionaries.Count == 0)
            this.Resources.MergedDictionaries.Add(rd);
        else
            this.Resources.MergedDictionaries[0] = rd;
    }

这适用于 xaml 文件,但我还想在后面的代码中更改视图模型的语言。

我的 ItemsControl 在 xaml:

<ItemsControl ItemsSource="{Binding ItemOperate}">
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type viewmodel:SelectableViewModel}">
                <Border x:Name="Border" Padding="0,8,0,8" BorderThickness="0 0 0 1" BorderBrush="{DynamicResource MaterialDesignDivider}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition SharedSizeGroup="Checkerz" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <ToggleButton VerticalAlignment="Center" IsChecked="{Binding IsSelected}"
                                      Style="{StaticResource MaterialDesignActionLightToggleButton}"
                                      Content="{Binding Code}" />
                        <StackPanel Margin="8 0 0 0" Grid.Column="7">
                            <TextBlock FontWeight="Bold" Text="{Binding Name}" />
                            <TextBlock Text="{Binding Description}" />
                        </StackPanel>
                    </Grid>
                </Border>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsSelected}" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="{DynamicResource MaterialDesignSelection}" />
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

像这样绑定到 ViewModel

public class SelectableViewModel : INotifyPropertyChanged
{ 
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (_isSelected == value) return;
            _isSelected = value;
            OnPropertyChanged();
        }
    }

    private char _code;
    public char Code
    {
        get { return _code; }
        set
        {
            if (_code == value) return;
            _code = value;
            OnPropertyChanged();
        }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value) return;
            _name = value;
            OnPropertyChanged();
        }
    }

    private string _description;
    public string Description
    {
        get { return _description; }
        set
        {
            if (_description == value) return;
            _description = value;
            OnPropertyChanged();
        }
    }
}

    public MainViewModel()
    {
        _itemOperate = CreateData();
    }

    private static ObservableCollection<SelectableViewModel> CreateData()
    {
        return new ObservableCollection<SelectableViewModel>
            {
                new SelectableViewModel
                {
                    Code = 'E', 
                    Name = "Erase",
                    Description = "Erase The MCU Chip By Page"
                },
                new SelectableViewModel
                {
                    Code = 'D',
                    Name = "Detect",
                    Description = "Detect The MCU Flash",
                },
                new SelectableViewModel
                {
                    Code = 'P',
                    Name = "Programming",
                    Description = "Programming The MCU Chip By Hex File",
                },
                new SelectableViewModel
                {
                    Code = 'V',
                    Name = "Verify",
                    Description = "Verify The Downing Code",
                },
                new SelectableViewModel
                {
                    Code ='L',
                    Name = "Lock",
                    Description = "Lock The Code To Protect The MCU",
                }
            };
    }

那么我应该如何更改我的模型 SelectableViewModel CodeNameDescription 的语言而不是使用此硬代码?谢谢!

我会建议你一个在运行时更改语言的解决方案。

  1. 创建资源管理器:

    public class CultureResources
    {
        private static bool isAvailableCulture;
        private static readonly List<CultureInfo> SupportedCultures = new List<CultureInfo>();
        private static ObjectDataProvider provider;
    
        public CultureResources()
        {
            GetAvailableCultures();
        }
    
            /// <summary>
            /// Gets automatically all supported cultures resource files.
            /// </summary>
            public void GetAvailableCultures()
            {
    
                if (!isAvailableCulture)
                {
                    var appStartupPath = AppDomain.CurrentDomain.BaseDirectory;
    
                    foreach (string dir in Directory.GetDirectories(appStartupPath))
                    {
                        try
                        {
                            DirectoryInfo dirinfo = new DirectoryInfo(dir);
                            var culture = CultureInfo.GetCultureInfo(dirinfo.Name);
                            SupportedCultures.Add(culture);
                        }
                        catch (ArgumentException)
                        {
                        }
                    }
                    isAvailableCulture = true;
                }
            }
    
            /// <summary>
            /// Retrieves the current resources based on the current culture info
            /// </summary>
            /// <returns></returns>
            public Resources GetResourceInstance()
            {
                return new Resources();
            }
    
            /// <summary>
            /// Gets the ObjectDataProvider wrapped with the current culture resource, to update all localized UIElements by calling ObjectDataProvider.Refresh()
            /// </summary>
            public static ObjectDataProvider ResourceProvider
            {
                get {
                    return provider ??
                           (provider = (ObjectDataProvider)System.Windows.Application.Current.FindResource("Resources"));
                }
            }
    
            /// <summary>
            /// Changes the culture
            /// </summary>
            /// <param name="culture"></param>
            public  void ChangeCulture(CultureInfo culture)
            {
                if (SupportedCultures.Contains(culture))
                {
                    Resources.Culture = culture;
                    ResourceProvider.Refresh();
                }
                else
                {
                    var ci = new CultureInfo("en");
    
                    Resources.Culture = ci;
                    ResourceProvider.Refresh();
                }
            }
    
            /// <summary>
            /// Sets english as default language
            /// </summary>
            public void SetDefaultCulture()
            {
                CultureInfo ci = new CultureInfo("en");
    
                Resources.Culture = ci;
                ResourceProvider.Refresh();
            }
    
            /// <summary>
            /// Returns localized resource specified by the key
            /// </summary>
            /// <param name="key">The key in the resources</param>
            /// <returns></returns>
            public static string GetValue(string key)
            {
                if (key == null) throw new ArgumentNullException();
                return Resources.ResourceManager.GetString(key, Resources.Culture);
            }
    
            /// <summary>
            /// Sets the new culture
            /// </summary>
            /// <param name="cultureInfo">  new CultureInfo("de-DE");  new CultureInfo("en-gb");</param>
            public void SetCulture(CultureInfo cultureInfo)
            {
    
                //get language short format - {de} {en} 
                var ci = new CultureInfo(cultureInfo.Name.Substring(0,2));
                ChangeCulture(ci);
                Thread.CurrentThread.CurrentCulture = cultureInfo;
                Thread.CurrentThread.CurrentUICulture = cultureInfo;
               // CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-GB");
    
            }
        }
    
  2. 根据需要为每种语言类型定义资源文件。 上面我已经为英语定义了默认值,为德语定义了第二个文件(你可以看到“.de”扩展名。所以你可以为任何其他语言做。 确保打开 Resources.resx 属性和 select 作为自定义工具,值 PublicResXFileCodeGenerator。为了通过对象提供者公开资源,此步骤是必要的。

  3. 通过 App.xaml 中的对象提供者注册资源提供者:

  4. 用法: 在 Xaml 中:

    Text="{Binding ResourcesText1, Source={StaticResource Resources}}"

来自 *.cs : Resources.ResourcesText1.

P.S。 更改区域性时,请确保从 CultureResouces.

调用 SetCulture 方法