枚舉的多語言顯示
關于枚舉類型的多語言顯示,其實就是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
}
浙公網安備 33010602011771號