65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 或 Silverlight 中的全球化

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (3投票s)

2010年3月14日

CPOL

3分钟阅读

viewsIcon

29882

downloadIcon

368

WPF 和 Silverlight 应用程序的动态全球化, 无需破坏设计时

引言

在这个 C# 演示中,我将展示如何向 WPF 或 Silverlight 应用程序添加全球化,并带有一些错误检测功能。这将使开发人员能够创建一个应用程序,用户可以选择以哪种语言显示信息以及其他文化设置,而不是基于他们的 Windows 设置。例如,在公共或集体使用的计算机上,应用程序可以允许用户选择他们的语言,并以该语言呈现应用程序。您可能会在提供就业申请和测试的程序中看到这一点。

另一个目标是在 Visual Studio 或 Expression Blend 的设计时使字符串可见。(请注意,需要提供 Common.dllCommonSL.dll,Expression Blend 才能看到字符串。)这允许您的美术师在开发人员完成后进入并像用户看到的那样审查应用程序。

代码

我们将创建一个名为 PublicResource 的类,它同时实现了 IValueConverterINotifyPropertyChanged。这个类用于使 resx 文件中通常不可用的部分变为 public。它还将包含一个在 XAML 中使用的转换器。

首先,创建一个从 ResourceManager 继承的子 private 类。其中一部分看起来与您的 resx 文件的常规 designer.cs 非常相似。请注意我们如何添加一种方法,如果未在两个 GetString() 方法中找到 string,则显示默认消息。

public class PublicResource : IValueConverter, INotifyPropertyChanged
{
  private class ResourceManagerWithErrors 
        : global::System.Resources.ResourceManager
  {
    public ResourceManagerWithErrors(Type resourceSource) 
        : base(resourceSource) { }
    public ResourceManagerWithErrors(string baseName, Assembly assembly) 
        : base(baseName, assembly) { }
    public ResourceManagerWithErrors(string baseName, Assembly assembly,
        Type usingResourceSet)
        : base(baseName, assembly, usingResourceSet) { }

    public string NotFoundMessage = "#Missing#";

    public override string GetString(string name)
    {
      return base.GetString(name) ?? NotFoundMessage + name;
    }

    public override string GetString(string name, CultureInfo culture)
    {
      return base.GetString(name, culture) ?? NotFoundMessage + name;
    }
  }

  private static ResourceManagerWithErrors _stringResourceManager;
  private static ResourceManagerWithErrors StringResourceManager
  {
    get
    {
      if (object.ReferenceEquals(_stringResourceManager, null))
      {
        _stringResourceManager = 
            new ResourceManagerWithErrors("WPFApplication1.Strings",
            typeof(PublicResource).Assembly);
        _stringResourceManager.NotFoundMessage = "#StringResourceMissing#";
      }
      return _stringResourceManager;
    }
  }

请务必将 WPFApplication1.Strings 替换为您的 resx 文件的命名空间和名称(不带 .resx)。

接下来,我们实现 IValueConverter,以便可以在 XAML 中使用该类。通过将查找字符串的逻辑移到转换器中,我们可以动态构建全球化的文本。

有一些错误检测,确保 value 已设置。我们稍后会讲到。请注意,我们使用 CurrentUICulture 查找 string,而不是传入的 culture。传入的 culture 是不会改变的全局 culture。

public object Convert(object value, Type targetType,
    object parameter, CultureInfo culture)
{
  if ((value == null) || !(value is string))
    return "set Binding Path/Source!";

  return StringResourceManager.GetString(
          (string)parameter,
          System.Threading.Thread.CurrentThread.CurrentUICulture);
}

public object ConvertBack(object value, Type targetType,
    object parameter, CultureInfo culture)
{
  throw new NotImplementedException("No reason to do this.");
}

接下来我们需要一个默认的 string。我们将绑定到它并使用 Converter 覆盖它。如果路径无法解析,转换器永远不会运行。我们将其设为常量,以便转换器始终运行。

public static string AString { get { return "AString"; } }

接下来我们需要某种方式来告诉应用程序更改 culture。我们通过通知每个人都将指向的单个属性已更改来做到这一点。如果使用生成的 resx 文件代码,请也为其设置 culture。

public event PropertyChangedEventHandler PropertyChanged;

public void ChangeCulture(string culture)
{
  // set App culture and the resource file culture
  System.Threading.Thread.CurrentThread.CurrentUICulture =
      new System.Globalization.CultureInfo(culture);
  System.Threading.Thread.CurrentThread.CurrentCulture =
          System.Threading.Thread.CurrentThread.CurrentUICulture;
  Strings.Culture = 
          System.Threading.Thread.CurrentThread.CurrentUICulture;

  // notify that the culture has changed
  PropertyChangedEventHandler handler = PropertyChanged;

  if (handler != null)
    handler(this, new PropertyChangedEventArgs("AString"));
}

最后,由于 PublicResource 的行为类似于一个 static 类,但我们无法在没有实例的情况下调用 NotifyCultureChanged,因此我们将引用保存到它自己的构造函数中。

public static PublicResource Myself;

public PublicResource() 
{ 
  Myself = this; 
}

这就完善了 PublicResource 类。让我们看看如何使用它。在 XAML 中,我们添加一个 TextBlock 并调用转换器。

xmlns:res="clr-namespace:WPFApplication1;assembly=Common"

<Window.Resources>
  <res:PublicResource x:Key="Resource"/>
</Window.Resources>

<TextBlock Text="{Binding Path=AString, 
    Source={StaticResource Resource}, Mode=OneWay,
    Converter={StaticResource Resource}, ConverterParameter=HelloWorld}"/>

请务必将 WPFApplication1Common 替换为查找 PublicResource 类的名称和程序集名称。

那么,这里会发生什么? Binding 会去查找 PublicResource 中名为 AString 的属性。这将作为 "AString" 返回。完成此操作后,转换器将执行。这会去查找适当的资源文件中的参数 HelloWorld,并根据当前的 culture 返回它映射到的任何内容。如果未在 resx 文件中找到 string,它将返回 #StringResourceMissing#HelloWorld。这在界面上很容易发现,而不是完全丢失的 string

要动态更改 culture,我们调用

PublicResource.Myself.ChangeCulture("es-ES");

我们需要设置完整的 culture 名称,而不仅仅是 "es"。

对于 Silverlight 应用程序,您还需要编辑客户端应用程序的 .csproj 文件。使用以逗号分隔的 resx 文件列表修改 SupportedCultures 标签。默认值不需要包含任何内容。这些代码必须与资源文件上的代码匹配。如果您希望 es-MX 和 es-ES 不同,那么您需要在两个地方都支持它们。

<SupportedCultures>en,de,es</SupportedCultures>

希望这可以帮助您进行国际化、全球化和本地化工作。

历史

  • 2010 年 3 月 14 日:初步发布
© . All rights reserved.