找回密码
 立即注册

QQ登录

只需一步,快速开始

thrall

超级版主

11

主题

170

帖子

1893

积分

超级版主

Rank: 8Rank: 8

积分
1893

活字格认证微信认证勋章

[杂谈灌水] 枚举的多语言显示

thrall
超级版主   /  发表于:2013-5-3 16:33  /   查看:4891  /  回复:0
关于枚举类型的多语言显示,其实就是Globalization的问题。解决方案当然不止一种,这里介绍一种可用性和扩展性的比较好的通用方法。



显然这里自己去实现自定义格式化,即通过IFormatable、IFormatProvider、ICustomFormatter等接口已达到Globalization有点小题大作了,而另外一个很容易想到的点是通过DiaplayMember实现显示值得自定义(对于简单Binding,例如ComboBox、ListBox等只用重载ToString就可以了)。



首先,我们希望Binding整个枚举类型的每一个值,也就是说,我们需要把这个枚举的所有值变成一个数据源,为了实现这一点,我们可以使用Enum上的helper方法Enum.GetValues(Type)来返回一个对所有值得枚举,然后依次添加到IList对象或者IListSource接口即可。
  1. if (!typeof(EnumType).IsEnum)
  2. {
  3.     throw new NotSupportedException("Can not support type: " + typeof(EnumType).FullName);
  4.     // It's better use resource version as below.
  5.     // throw new NotSupportedException(SR.GetString("TYPE_NOT_SUPPORT",  typeof(EnumType).FullName));
  6. }

  7. // Use Enum helper enumerator list all enum values and add to current context.
  8. foreach (EnumType value in Enum.GetValues(typeof(EnumType)))
  9. {
  10.     //TODO: add each value to IList
  11.     base.Add(new EnumAdapter(value));
  12. }
复制代码

然后,取到了值,由于我们希望自定义Binding显示,那么需要对枚举值进行封装,而在这个封装里面,我们可以实现多语言的支持。
  1. /// <summary>
  2. ///   Enum value adapter, used to get values from each Cultures.
  3. /// </summary>
  4. public sealed class EnumAdapter
  5. {
  6.     /**//// <summary>
  7.     ///   Storage the actual Enum value.
  8.     /// </summary>
  9.     private EnumType _value;

  10.     /**//// <summary>
  11.     ///   Constructor an <see cref="EnumAdapter"/>.
  12.     /// </summary>
  13.     /// <param name="value">The enum value.</param>
  14.     /// <exception cref="">
  15.     ///   
  16.     /// </exception>
  17.     public EnumAdapter(EnumType value)
  18.     {
  19.         if (!Enum.IsDefined(typeof(EnumType), value))
  20.         {
  21.             throw new ArgumentException(string.Format("{0} is not defined in {1}", value, typeof(EnumType).Name), "value");
  22.             // It's better use resource version as below.
  23.             // throw new ArgumentException(SR.GetString("ENUM_NOT_DEFINED_FMT_KEY", value, typeof(EnumType).Name), "value");
  24.         }
  25.         _value = value;
  26.     }

  27.     /**//// <summary>
  28.     ///   Gets the actual enum value.
  29.     /// </summary>
  30.     public EnumType Value
  31.     {
  32.         get { return _value; }
  33.     }

  34.     /**//// <summary>
  35.     ///   Gets the display value for enum value by search local resource with currrent UI lture
  36.     ///   and special key which is concated from Enum type name and Enum value name.
  37.     /// </summary>
  38.     /// <remarks>
  39.     ///   This would get correct display value by accessing location resource with current UI Culture.
  40.     /// </remarks>
  41.     public string DisplayValue
  42.     {
  43.         get { return SR.GetString(string.Format("{0}.{1}", typeof(EnumType).Name, _value.ToString())); }
  44.     }

  45.     //TODO: If you want more, please add below
  46. }
复制代码

至此,整个功能的框架已经完成,下面我们来看看一些细节——如何对资源读取和管理的封装:
  1. /// <summary>
  2. ///   Constructor a new <see cref="SR"/>.
  3. /// </summary>
  4. internal SR()
  5. {
  6.     //TODO: If you modified resource location, please update here
  7.     this.resources = new System.Resources.ResourceManager(
  8.         string.Concat(typeof(EnumAdapter).Namespace, ".Resource"),
  9.         base.GetType().Assembly);
  10. }

  11. /**//// <summary>
  12. ///   Get singleton instance.
  13. /// </summary>
  14. /// <returns>A singleton <see cref="SR"/></returns>
  15. private static SR GetLoader()
  16. {
  17.     if (loader == null)
  18.     {
  19.         lock (SR.InternalSyncObject)
  20.         {
  21.             if (loader == null)
  22.             {
  23.                 loader = new SR();
  24.             }
  25.         }
  26.     }
  27.     return loader;
  28. }

  29. /**//// <summary>
  30. ///   Gets an object from resources by special key, which provided by <paramref name="name"/>.
  31. /// </summary>
  32. /// <param name="name">Resource accessed key</param>
  33. /// <returns>return stored object in resource. if resource not found, return <paramref name="name"/> as object.</returns>
  34. public static object GetObject(string name)
  35. {
  36.     SR loader = GetLoader();
  37.     if (loader == null)
  38.     {
  39.         return null;
  40.     }
  41.     try
  42.     {
  43.         return loader.resources.GetObject(name, Culture);
  44.     }
  45.     catch { }
  46.     return name;
  47. }

  48. /**//// <summary>
  49. ///   Gets a string from resources by special key, which provided by <paramref name="name"/>.
  50. /// </summary>
  51. /// <param name="name">Resource accessed key</param>
  52. /// <returns>return stored string in resource. If resource not found, retuen <paramref name="name"/> as result.</returns>
  53. public static string GetString(string name)
  54. {
  55.     SR loader = GetLoader();
  56.     if (loader == null)
  57.     {
  58.         return null;
  59.     }
  60.     try
  61.     {
  62.         return loader.resources.GetString(name, Culture);
  63.     }
  64.     catch { }
  65.     return name;
  66. }

  67. /**//// <summary>
  68. ///   Gets a formatted string from resources by special key, which provided by <paramref name="name"/> and optional parameters.
  69. /// </summary>
  70. /// <param name="name">Resource accessed key</param>
  71. /// <param name="args">format arguments.</param>
  72. /// <returns>return stored string in resource. If resource not found, use <paramref name="name"/> as formator, return the formatted string.</retur
  73. public static string GetString(string name, params object[] args)
  74. {
  75.     SR loader = GetLoader();
  76.     if (loader == null)
  77.     {
  78.         return null;
  79.     }
  80.     string format = name;
  81.     try
  82.     {
  83.         format = loader.resources.GetString(name, Culture);
  84.     }
  85.     catch { }

  86.     if ((args == null) || (args.Length <= 0))
  87.     {
  88.         return format;
  89.     }

  90.     // It's better cut long arg for formating.
  91.     for (int i = 0; i < args.Length; i++)
  92.     {
  93.         string arg = args[i] as string;
  94.         if ((arg != null) &amp;&amp; (arg.Length > 0x400))
  95.         {
  96.             args[i] = arg.Substring(0, 0x3fd) + "";
  97.         }
  98.     }
  99.     return string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args);
  100. }
复制代码

OK,大功告成,有了这么一个封装,在应用里就可以简单的这么几句够搞定。
  1. private void Form1_Load(object sender, EventArgs e)
  2. {
  3.     this.comboBox1.DataSource = new EnumDataSource<Sex>();
  4.     this.comboBox1.DisplayMember = "DisplayValue";
  5.     this.comboBox1.ValueMember = "Value";
  6. }

  7. public enum Sex
  8. {
  9.     Male,
  10.     Female
  11. }
复制代码
您需要登录后才可以回帖 登录 | 立即注册
返回顶部