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

标签 c# wpf xaml resourcedictionary

我想通过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 文件效果很好,但我也想在后面的代码中更改 View 模型的语言。

xaml 中的我的 ItemsControl:

<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 的绑定(bind)如下:

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. 根据需要为每种语言类型定义资源文件。 enter image description here 上面我已经定义了英语的默认值和德语的第二个文件(您可以看到“.de”扩展名。对于任何其他语言也是如此。 确保打开 Resources.resx 属性并选择值 PublicResXFileCodeGenerator 作为自定义工具。为了通过对象提供者公开资源,此步骤是必要的。 enter image description here

  3. 通过 App.xaml 中的对象提供程序注册资源提供程序: enter image description here

  4. 用法: 在 Xaml 中:

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

来自 *.cs:Resources.ResourcesText1

附注 当您更改区域性时,请确保从 CultureResouces 中调用 SetCulture 方法。

关于c# - 如何在运行时使用资源字典更改 UI 语言?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45407108/

相关文章:

c# - RxUI ObservableAsPropertyHelper 不适用于 XAML 绑定(bind)

c# - 将样式中的 Setter 值绑定(bind)到主模型

c# - 为什么逻辑 AND 运算的明显错误结果取消了 FOR 循环迭代

c# - 是否可以在不序列化的情况下将对象从 SilverLight 传递到 JavaScript?

c# - WPF。如何使分隔符拉伸(stretch)到菜单宽度?

c# - 没有错误或异常,但是代码无法在WPF应用程序中播放音频文件

c# - WPF ComboboxItem 绑定(bind)

c# - 在 WP7 上释放 Application.GetResourceStream 返回的底层 Stream

c# - 将 KeyUp 作为参数传递 WPF 命令绑定(bind)文本框

c# - 在 'code behind' 中设置的 WPF 控件属性,之后忽略绑定(bind)