【问题标题】:How to change UI language using resource dictionary at run time?如何在运行时使用资源字典更改 UI 语言?
【发布时间】:2017-07-31 03:33:51
【问题描述】:

我想通过 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 文件,但我还想在后面的代码中更改视图模型的语言。

我在 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

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 的语言而不是使用这个硬代码?谢谢!

【问题讨论】:

    标签: c# wpf xaml resourcedictionary


    【解决方案1】:

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

    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 属性并选择值 PublicResXFileCodeGenerator 作为自定义工具。为了通过对象提供者公开资源,此步骤是必要的。

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

    4. 用法: 在 Xaml 中:

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

    来自 *.cs :Resources.ResourcesText1

    附: 当您更改文化时,请务必从 CultureResouces 调用 SetCulture 方法。

    【讨论】:

    • 感谢您的回答。但是当我调用 SetCulture() 时,它给了我error: 'Resources' resource not found 我错过了什么吗?
    • 您是否定义了资源文件? Resources.resx 和 Resources.de.resx?
    • 这种方式应该如何获取当前文化并根据当前值设置新文化?
    • 如何获得当前文化: varculture = Thread.CurrentThread.CurrentCulture;你如何改变文化:例如:new CultureResources().SetCulture(new CultureInfo("de-DE"));
    • 这个解决方案似乎有效,除了我的项目中的ItemsControl,这是我要求的问题。我已经更改了ItemsControl 视图模型,例如:Name = Resources.ChipErase 在后面的代码中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    相关资源
    最近更新 更多