背景
- C# + XAML
- 列挙の値に対応する文字列を表示したい
//演算子
public enum Operator
{
PLUS, MINUS, MULTIPLY, DIVIDE,
}
<!--演算子-->
<ComboBox ItemsSource="{Binding Path=Operators}" />
ここでは、ComboBoxのItemsSource
を、Operator
列挙型のコレクションとバインドしています。
他に何も書かなければ、ComboBoxの選択肢は、列挙の値(PLUS
など)がそのまま文字列として表示されますね。
でも、Operator
列挙型は演算子なので、「+」や「-」を表示したいんです!
BindingにConverterを付けると…
まず思いつくのが、バインドにコンバーターを指定する方法です。
<!--演算子-->
<ComboBox ItemsSource="{Binding Path=Operators,
Converter={StaticResource converter}}" />
しかしこれは、バインドしている対象、ここでは「Operator
列挙型のコレクション」をコンバートするコンバーターを指定するものです。
これでもいいのですが、コレクションのコンバーターではなく、やっぱり個々のアイテムのコンバーターにしたいですよねぇ。
TypeConverter属性!
そこでTypeConverter
属性の登場です!
//演算子
[TypeConverter(typeof(OperatorConverter))] //コンバーターの指定
public enum Operator
{
PLUS, MINUS, MULTIPLY, DIVIDE,
}
上記のようにOperator
列挙型にTypeConverter
属性を付けると、Operator
列挙型と他の型とのコンバートが必要になると、指定したクラス(ここではOperatorConverter
)がコンバーターとして使われます。
ここで作っているOperatorConverter
クラスは列挙型に付けるコンバーターなので、System.ComponentModel.EnumConverter
クラスを継承元にして定義します。
//演算子と文字列のコンバーター
public class OperatorConverter : System.ComponentModel.EnumConverter
{
//コンストラクター
public OperatorConverter(Type type) : base(type)
{
}
//演算子から文字列への変換
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(string)) throw new NotSupportedException();
try
{
Operator ope = (Operator)value;
return ope.GetString();//Operatorをstringに変換する拡張メソッド(詳細は省略)
}
catch
{
throw new NotSupportedException();
}
}
//文字列から演算子への変換
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
//(略)
}
}
ConvertTo
メソッドに他の型へのコンバート、ConvertFrom
メソッドに他の型からのコンバート処理を記述します。
<!--演算子-->
<ComboBox ItemsSource="{Binding Path=Operators}" />
これで、XAMLはもとのままですが、ComboBoxの選択肢はPLUS
など列挙の値そのままではなく、OperatorConverter.ConvertTo
メソッドで変換した値になりました。
めでたし、めでたし!