「これは私の理想的なソリューションよりも複雑です」という意味がわかりません。私はあなたのものとは異なるこれを行う方法を持っていますが、それほど複雑ではないかもしれません. 私のやり方では、前もってオーバーヘッドが増えますが、アプリケーションで使用すればするほど報われます。アプリケーションをローカライズできるように準備し、各列挙値に属性を追加する必要がないことを意味します。
1) Resource Manager キャッシュを作成する
この部分はオプションです。ただし、私のように複数のリソース ファイルを何度も使用すると、リフレクションの量が減り、パフォーマンスが向上する可能性があります。
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Resources;
namespace AppResourceLib.Public.Reflection
{
internal static class ResourceManagerCache
{
private static Dictionary<Type, ResourceManager> _resourceManagerMap =
new Dictionary<Type, ResourceManager>();
public static ResourceManager GetResourceManager(Type resourceType)
{
ResourceManager resourceManager = null;
// Make sure the type is valid.
if (null != resourceType)
{
// Try getting the cached resource manager.
if (!ResourceManagerCache._resourceManagerMap.TryGetValue(resourceType, out resourceManager))
{
// If it is not in the cache create it.
resourceManager = resourceType.InvokeMember(
"ResourceManager",
(BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic),
null,
null,
null) as ResourceManager;
// If it was created, add the resource manager to the cache.
if (null != resourceManager)
{
ResourceManagerCache._resourceManagerMap.Add(resourceType, resourceManager);
}
}
}
return resourceManager;
}
}
}
2) ローカライズされた説明属性を作成する
これは、列挙型に適用する属性です。これの優れた点は、列挙型宣言の上に一度だけ、各列挙型に属性を追加する必要がないことです。
using System;
using System.ComponentModel;
namespace AppResourceLib.Public.Reflection
{
/// <summary>
/// A resource type attribute that can be applied to enumerations.
/// </summary>
[AttributeUsage(AttributeTargets.Enum)]
public sealed class LocalizedDescriptionAttribute : Attribute
{
/// <summary>
/// The type of resource associated with the enum type.
/// </summary>
private Type _resourceType;
public LocalizedDescriptionAttribute(Type resourceType)
{
this._resourceType = resourceType;
}
/// <summary>
/// The type of resource associated with the enum type.
/// </summary>
public Type ResourceType
{
get
{
return this._resourceType;
}
}
}
}
3) ローカライズされた説明コンバーターを作成する
これにより、列挙値が文字列リソース (.resx) ファイルで指定する文字列に変換されます。
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Windows.Data;
namespace AppResourceLib.Public.Reflection
{
[ValueConversion(typeof(Object), typeof(String))]
public class LocalizedDescriptionConverter : IValueConverter
{
public Object Convert(Object value, Type targetType, Object param, CultureInfo cultureInfo)
{
String description = null;
if (null != value)
{
// If everything fails then at least return the value.ToString().
description = value.ToString();
// Get the LocalizedDescriptionAttribute of the object.
LocalizedDescriptionAttribute attribute =
value.GetType().GetCustomAttribute(typeof(LocalizedDescriptionAttribute))
as LocalizedDescriptionAttribute;
// Make sure we found a LocalizedDescriptionAttribute.
if (null != attribute)
{
ResourceManager resourceManager =
ResourceManagerCache.GetResourceManager(attribute.ResourceType);
if (null != resourceManager)
{
// Use the ResourceManager to get the description you gave the object value.
// Here we just use the object value.ToString() (the name of the object) to get
// the string in the .resx file. The only constraint here is that you have to
// name your object description strings in the .resx file the same as your objects.
// The benefit is that you only have to declare the LocalizedDescriptionAttribute
// above the object type, not an attribute over every object.
// And this way is localizable.
description = resourceManager.GetString(value.ToString(), cultureInfo);
String formatString = (param as String);
// If a format string was passed in as a parameter,
// make a string out of that.
if (!String.IsNullOrEmpty(formatString))
{
formatString = formatString.Replace("\\t", "\t");
formatString = formatString.Replace("\\n", "\n");
formatString = formatString.Replace("\\r", "\r");
description = String.Format(formatString, value.ToString(), description);
}
}
}
}
return description;
}
public Object ConvertBack(Object value, Type targetType, Object param, CultureInfo cultureInfo)
{
throw new NotImplementedException();
return null;
}
}
}
4) リソース (.resx) 文字列ファイルを作成する
次に、Enums キー値スタイルに必要な説明を含むリソース ファイルを作成します。つまり、文字列リソースの「名前」列には個々の列挙型の正確な名前を入力し、「値」列にはその列挙型を変換するときに取得する文字列を入力します。
たとえば、次の列挙型があるとします。
public enum MyColors
{
Black,
Blue,
White
}
次に、文字列リソース ファイルは次のようになります...
名前 | 価値
ブラック | ダークカラー
ブルー | 写真 クールな色
ホワイト | 明るい色
5) 属性を持つ列挙型を作成する
最後に、LocalizedDescription を使用して Enum 宣言を行います。LocalizedDescription 属性に渡すパラメーターは、文字列リソース ファイルの種類です。コンバーターを使用すると、列挙型の属性が表示され、リソース ファイルが取得され、特定の列挙値の文字列値に一致するキー文字列が検索され、リソース ファイルから値が変換された文字列として返されます。
using AppResourceLib.Public;
using AppResourceLib.Public.Reflection;
namespace MyEnums
{
[LocalizedDescription(typeof(MyColorStrings))]
public enum MyColors
{
Black,
Blue,
White
}
}
このアプローチの主な欠点は、リソース ファイルの "Name" キーが列挙値の名前と一致する場合にのみ機能することです。これは、各列挙型に説明属性を指定せずにリソース ファイル内の文字列値を参照する唯一の方法です。では、値を表示するためにこれをどのように使用しますか? ここに例があります...
xaml コードでは、列挙型の値を UI 要素に取得するデータ プロバイダーを作成する必要があります (ここでは ComboBox を使用しています...)。次に、コンバーターを使用可能にし、UI 要素をテンプレート化して enum コンバーターを使用するようにします。だからここに行く...
<!-- Enum Colors -->
<ObjectDataProvider x:Key="MyColorEnums"
MethodName="GetValues"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="MyColors"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<!-- Enum Type Converter -->
<LocalizedDescriptionConverter x:Key="EnumConverter"/>
<!-- Dropdown Expand ComboBox Template -->
<DataTemplate x:Key="MyColorsComboBoxTemplate">
<Label Content="{Binding Path=., Mode=OneWay,
Converter={StaticResource EnumConverter}}"
Height="Auto" Margin="0" VerticalAlignment="Center"/>
</DataTemplate>
<!-- And finally the ComboBox that will display all of your enum values
but will use the strings from the resource file instead of enum.ToString() -->
<ComboBox Width="80" HorizontalAlignment="Left"
ItemTemplate="{StaticResource MyColorsComboBoxTemplate}"
ItemsSource="{Binding Source={StaticResource MyColorEnums}}">
うわー、すみません、これはとても長いです。これがあなたにとって複雑すぎるかどうかはわかりませんが、別のオプションです。それが役に立てば幸い!