• 枚举的多语言显示


    早上看到jhh0111昨天关于枚举的双语显示问题的帖子,中午想了想,其实这就是一个Globalization的问题,虽然jhh0111的方案可以工作,但是扩展性不强——当枚举数量很大时可用性很低;另外,如果绑定到其他控件(比如Grid控件)也会有一些问题。
    这里给出一个通用的解决方案,虽然复杂了一些,但是可用性和扩张性均有大大提高。
    显然这里自己去实现自定义格式化,即通过IFormatable、IFormatProvider、ICustomFormatter等接口已达到Globalization有点小题大作了,而另外一个很容易想到的点是通过DiaplayMember实现显示值得自定义(对于简单Binding,例如ComboBox、ListBox等只用重载ToString就可以了)。
    既然有了方向,那就动手了。
    首先,我们希望Binding整个枚举类型的每一个值,也就是说,我们需要把这个枚举的所有值变成一个数据源,为了实现这一点,我们可以使用Enum上的helper方法Enum.GetValues(Type)来返回一个对所有值得枚举,然后依次添加到IList对象或者IListSource接口即可。
     1if (!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
     8// Use Enum helper enumerator list all enum values and add to current context.
     9foreach (EnumType value in Enum.GetValues(typeof(EnumType)))
    10{
    11    //TODO: add each value to IList
    12    base.Add(new EnumAdapter(value));

    13}
    然后,取到了值,由于我们希望自定义Binding显示,那么需要对枚举值进行封装,而在这个封装里面,我们可以实现多语言的支持。
     1/// <summary>
     2///   Enum value adapter, used to get values from each Cultures.
     3/// </summary>

     4public sealed class EnumAdapter
     5{
     6    /// <summary>
     7    ///   Storage the actual Enum value.
     8    /// </summary>

     9    private EnumType _value;
    10
    11    /// <summary>
    12    ///   Constructor an <see cref="EnumAdapter"/>.
    13    /// </summary>
    14    /// <param name="value">The enum value.</param>
    15    /// <exception cref="">
    16    ///   
    17    /// </exception>

    18    public EnumAdapter(EnumType value)
    19    {
    20        if (!Enum.IsDefined(typeof(EnumType), value))
    21        {
    22            throw new ArgumentException(string.Format("{0} is not defined in {1}", value, typeof(EnumType).Name), "value");
    23            // It's better use resource version as below.
    24            // throw new ArgumentException(SR.GetString("ENUM_NOT_DEFINED_FMT_KEY", value, typeof(EnumType).Name), "value");
    25        }

    26        _value = value;
    27    }

    28
    29    /// <summary>
    30    ///   Gets the actual enum value.
    31    /// </summary>

    32    public EnumType Value
    33    {
    34        get return _value; }
    35    }

    36
    37    /// <summary>
    38    ///   Gets the display value for enum value by search local resource with currrent UI culture 
    39    ///   and special key which is concated from Enum type name and Enum value name.
    40    /// </summary>
    41    /// <remarks>
    42    ///   This would get correct display value by accessing location resource with current UI Culture.
    43    /// </remarks>

    44    public string DisplayValue
    45    {
    46        get return SR.GetString(string.Format("{0}.{1}"typeof(EnumType).Name, _value.ToString())); }
    47    }

    48
    49    //TODO: If you want more, please add below
    50}
    至此,整个功能的框架已经完成,下面我们来看看一些细节——如何对资源读取和管理的封装:
      1/// <summary>
      2///   Constructor a new <see cref="SR"/>.
      3/// </summary>

      4internal 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
     12/// <summary>
     13///   Get singleton instance.
     14/// </summary>
     15/// <returns>A singleton <see cref="SR"/></returns>

     16private static SR GetLoader()
     17{
     18    if (loader == null)
     19    {
     20        lock (SR.InternalSyncObject)
     21        {
     22            if (loader == null)
     23            {
     24                loader = new SR();
     25            }

     26        }

     27    }

     28    return loader;
     29}

     30
     31/// <summary>
     32///   Gets an object from resources by special key, which provided by <paramref name="name"/>.
     33/// </summary>
     34/// <param name="name">Resource accessed key</param>
     35/// <returns>return stored object in resource. if resource not found, return <paramref name="name"/> as object.</returns>

     36public static object GetObject(string name)
     37{
     38    SR loader = GetLoader();
     39    if (loader == null)
     40    {
     41        return null;
     42    }

     43    try
     44    {
     45        return loader.resources.GetObject(name, Culture);
     46    }

     47    catch { }
     48    return name;
     49}

     50
     51/// <summary>
     52///   Gets a string from resources by special key, which provided by <paramref name="name"/>.
     53/// </summary>
     54/// <param name="name">Resource accessed key</param>
     55/// <returns>return stored string in resource. If resource not found, retuen <paramref name="name"/> as result.</returns>

     56public static string GetString(string name)
     57{
     58    SR loader = GetLoader();
     59    if (loader == null)
     60    {
     61        return null;
     62    }

     63    try
     64    {
     65        return loader.resources.GetString(name, Culture);
     66    }

     67    catch { }
     68    return name;
     69}

     70
     71/// <summary>
     72///   Gets a formatted string from resources by special key, which provided by <paramref name="name"/> and optional parameters.
     73/// </summary>
     74/// <param name="name">Resource accessed key</param>
     75/// <param name="args">format arguments.</param>
     76/// <returns>return stored string in resource. If resource not found, use <paramref name="name"/> as formator, return the formatted string.</retur
     77public static string GetString(string name, params object[] args)

     78{
     79    SR loader = GetLoader();
     80    if (loader == null)
     81    {
     82        return null;
     83    }

     84    string format = name;
     85    try
     86    {
     87        format = loader.resources.GetString(name, Culture);
     88    }

     89    catch { }
     90
     91    if ((args == null|| (args.Length <= 0))
     92    {
     93        return format;
     94    }

     95
     96    // It's better cut long arg for formating.
     97    for (int i = 0; i < args.Length; i++)
     98    {
     99        string arg = args[i] as string;
    100        if ((arg != null&& (arg.Length > 0x400))
    101        {
    102            args[i] = arg.Substring(00x3fd+ "";
    103        }

    104    }

    105    return string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args);
    106}
    OK,大功告成,有了这么一个封装,在应用里就可以简单的这么几句够搞定。
     1private 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
     8public enum Sex
     9{
    10    Male,
    11    Female
    12}
    你可以从这里下载本篇中的相关示例代码:
    https://files.cnblogs.com/winkingzhang/Demo_2008_03_25.rar
  • 相关阅读:
    [Android] ImageView.ScaleType设置图解 【转载】
    ASP.NET Web API 配置返回的json字段的格式以及Action返回HttpResponseMessage类型和IHttpActionResult类型
    ASP.NET Web API 上传文件
    ASP.NET Web API 全局权限和全局异常处理
    ASP.NET Web API 中的异常处理(转载)
    ASP.NET Web API 2 中的属性路由使用(转载)
    使用ASP.NET Web API自带的类库实现对CORS的支持(在开发中使用这种方式)(转载)
    通过扩展让ASP.NET Web API支持W3C的CORS规范(转载)
    IoC容器Autofac
    C#开发微信公众平台-就这么简单(附Demo)(转载)
  • 原文地址:https://www.cnblogs.com/winkingzhang/p/1121315.html
Copyright © 2020-2023  润新知