課題
Enum を定義して、それを一覧等に表示する際、Enum の値をそのまま使えない事はままある。例えば、プロジェクトの制約で Enum に日本語を使ってはいけない場合や、Enum 値を数字から始めたいが、数字から始まる文字列は使えないため、別の名称で定義している場合等だ。その場合、変換用のメソッドと変換後の値の表示用プロパティ等を新たに用意したりするのだが、私の場合、変換に関しては、Attirubte の設定と Enum の拡張メソッドの作成で解決することが多い。
public enum Apple
{
[Description("ふじ")]
Fuji,
[Description("紅玉")]
Kogyoku,
[Description("陸奥")]
Mutsu,
[Description("23号ふじ")]
Fuji23,
[Description("47号紅玉")]
Kogyoku47,
}
public static class EnumsExtensions
{
// Enum の拡張メソッド。自身に設定されている Description Attribute の値を返す
public static string GetDescription(this Enum value)
{
var field = value.GetType().GetField(value.ToString());
// field が null になることは無いが、警告回避のために null 条件演算子を使用
var attr = field?.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute;
return attr?.Description ?? string.Empty;
}
}
これは結構便利だが、一覧等に Bind して表示する場合に、表示用の string プロパティを用意しなければならないという問題を抱えていた。この表示用プロパティは、Entity が巨大だと結構邪魔になっていた。また、表示用プロパティの代わりに Convereter を利用する方法もあるが、Enum 型の数だけ用意しなければならないのでは無いかと考え、今まで表示用プロパティを新たに設ける形で対応していた。
解決方法
上記の課題に対して、汎用的な Converter を用意できないかと考えて、次のようなものを作ってみた。
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace EnumConverter.ViewModels
{
public class EnumToDescriptionConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> value?.GetType().IsEnum ?? false
? ((Enum)value).GetDescription()
: string.Empty;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => null;
public override object ProvideValue(IServiceProvider serviceProvider) => this;
}
}
<DataGridTextColumn Width="100" Binding="{Binding Apple, Converter={vm:EnumToDescriptionConverter}}" />
終わりに
この Converter により、表示用プロパティから解放されました。
更新履歴
2023/01/31:
@albireo 様から指摘を受けてコードを修正しました。ありがとうございます。例外処理の部分を削除し、拡張メソッドの書き方を修正しました。