枚举的多语言显示

关于枚举类型的多语言显示,其实就是Globalization的问题。解决方案当然不止一种,这里介绍一种可用性和扩展性的比较好的通用方法。

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

首先,我们希望Binding整个枚举类型的每一个值,也就是说,我们需要把这个枚举的所有值变成一个数据源,为了实现这一点,我们可以使用Enum上的helper方法Enum.GetValues(Type)来返回一个对所有值得枚举,然后依次添加到IList对象或者IListSource接口即可。

if (!typeof(EnumType).IsEnum)
{
    throw new NotSupportedException("Can not support type: " + typeof(EnumType).FullName);
    // It's better use resource version as below.
    // throw new NotSupportedException(SR.GetString("TYPE_NOT_SUPPORT",  typeof(EnumType).FullName));
}

// Use Enum helper enumerator list all enum values and add to current context.
foreach (EnumType value in Enum.GetValues(typeof(EnumType)))
{
    //TODO: add each value to IList
    base.Add(new EnumAdapter(value));
}

然后,取到了值,由于我们希望自定义Binding显示,那么需要对枚举值进行封装,而在这个封装里面,我们可以实现多语言的支持。

/// <summary>
///   Enum value adapter, used to get values from each Cultures.
/// </summary>
public sealed class EnumAdapter
{
    /**//// <summary>
    ///   Storage the actual Enum value.
    /// </summary>
    private EnumType _value;

    /**//// <summary>
    ///   Constructor an <see cref="EnumAdapter"/>.
    /// </summary>
    /// <param name="value">The enum value.</param>
    /// <exception cref="">
    ///   
    /// </exception>
    public EnumAdapter(EnumType value)
    {
        if (!Enum.IsDefined(typeof(EnumType), value))
        {
            throw new ArgumentException(string.Format("{0} is not defined in {1}", value, typeof(EnumType).Name), "value");
            // It's better use resource version as below.
            // throw new ArgumentException(SR.GetString("ENUM_NOT_DEFINED_FMT_KEY", value, typeof(EnumType).Name), "value");
        }
        _value = value;
    }

    /**//// <summary>
    ///   Gets the actual enum value.
    /// </summary>
    public EnumType Value
    {
        get { return _value; }
    }

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

    //TODO: If you want more, please add below
}

至此,整个功能的框架已经完成,下面我们来看看一些细节——如何对资源读取和管理的封装:

/// <summary>
///   Constructor a new <see cref="SR"/>.
/// </summary>
internal SR()
{
    //TODO: If you modified resource location, please update here
    this.resources = new System.Resources.ResourceManager(
        string.Concat(typeof(EnumAdapter).Namespace, ".Resource"), 
        base.GetType().Assembly);
}

/**//// <summary>
///   Get singleton instance.
/// </summary>
/// <returns>A singleton <see cref="SR"/></returns>
private static SR GetLoader()
{
    if (loader == null)
    {
        lock (SR.InternalSyncObject)
        {
            if (loader == null)
            {
                loader = new SR();
            }
        }
    }
    return loader;
}

/**//// <summary>
///   Gets an object from resources by special key, which provided by <paramref name="name"/>.
/// </summary>
/// <param name="name">Resource accessed key</param>
/// <returns>return stored object in resource. if resource not found, return <paramref name="name"/> as object.</returns>
public static object GetObject(string name)
{
    SR loader = GetLoader();
    if (loader == null)
    {
        return null;
    }
    try
    {
        return loader.resources.GetObject(name, Culture);
    }
    catch { }
    return name;
}

/**//// <summary>
///   Gets a string from resources by special key, which provided by <paramref name="name"/>.
/// </summary>
/// <param name="name">Resource accessed key</param>
/// <returns>return stored string in resource. If resource not found, retuen <paramref name="name"/> as result.</returns>
public static string GetString(string name)
{
    SR loader = GetLoader();
    if (loader == null)
    {
        return null;
    }
    try
    {
        return loader.resources.GetString(name, Culture);
    }
    catch { }
    return name;
}

/**//// <summary>
///   Gets a formatted string from resources by special key, which provided by <paramref name="name"/> and optional parameters.
/// </summary>
/// <param name="name">Resource accessed key</param>
/// <param name="args">format arguments.</param>
/// <returns>return stored string in resource. If resource not found, use <paramref name="name"/> as formator, return the formatted string.</retur
public static string GetString(string name, params object[] args)
{
    SR loader = GetLoader();
    if (loader == null)
    {
        return null;
    }
    string format = name;
    try
    {
        format = loader.resources.GetString(name, Culture);
    }
    catch { }

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

    // It's better cut long arg for formating.
    for (int i = 0; i < args.Length; i++)
    {
        string arg = args[i] as string;
        if ((arg != null) && (arg.Length > 0x400))
        {
            args[i] = arg.Substring(0, 0x3fd) + "";
        }
    }
    return string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args);
}

OK,大功告成,有了这么一个封装,在应用里就可以简单的这么几句够搞定。

private void Form1_Load(object sender, EventArgs e)
{
    this.comboBox1.DataSource = new EnumDataSource<Sex>();
    this.comboBox1.DisplayMember = "DisplayValue";
    this.comboBox1.ValueMember = "Value";
}

public enum Sex
{
    Male,
    Female
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PPV课数据科学社区

【学习】七天搞定SAS(二):基本操作(判断、运算、基本函数)

? 今天开始注重变量操作。 SAS生成新变量 SAS支持基本的加减乘除,值得一提的是它的**代表指数,而不是^。* Modify homegarden dat...

49140
来自专栏智能大石头

C++返回值优化RVO

返回值优化,是一种属于编译器的技术,它通过转换源代码和对象的创建来加快源代码的执行速度。RVO = return value optimization。 测试...

33090
来自专栏Android知识点总结

看得见的数据结构Android版之双链表篇

7710
来自专栏张善友的专栏

如何结合IbatisNet的LIST遍历实现模糊查询

我仿照Java的Spring+Ibatis+Struct用Castle+IBatisNet+Asp.net的开发框架的DAO的基类:BaseSqlMapDao内...

24490
来自专栏技术沉淀

Ruby练习四

11940
来自专栏积累沉淀

研究MapReduce源码之实现自定义LineRecordReader完成多行读取文件内容

TextInputFormat是Hadoop默认的数据输入格式,但是它只能一行一行的读记录,如果要读取多行怎么办? 很简单 自己写一个输入格式,然后写一个对...

22190
来自专栏用户画像

微博订阅评论

参考:http://open.weibo.com/wiki/%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81

13310
来自专栏圣杰的专栏

Windbg分析高内存占用问题

最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声。为了缓解现场的情况, 客户都是手...

22830
来自专栏数据结构与算法

Atcoder训练计划

https://www.cnblogs.com/zwfymqz/p/9706027.html

20140
来自专栏菩提树下的杨过

温故而知新:设计模式之原型模式(Prototype)

原型模式个人以为最适合的场景:参照现有的某一个对象实例,快速得到多个完整的实例副本。(通常是深拷贝的副本) 深拷贝在c#中实现的最简单方式莫过于通过反序列化得到...

24650

扫码关注云+社区

领取腾讯云代金券