Enumとラジオボタンをバインドする際にはまった点があった。
利用するケース
Enumで定義した項目を選択肢としてラジオボタンで選ぶようなケース。今作っているプログラムでも、同様なケースがあったので使ってみた。
ラジオボタンはBool値なので、Enumのプロパティとの間でバインドする場合、値の変換が必要になる。
値の変換
とりあえずWebを検索して、それらしいサイトから情報を仕入れた結果、以下の様にするということが分かった。
- EnumとBoolの変換クラスを作成する。
変換クラスはSystem.Windows.Data.IValueConverterのインターフェースを持ったもの。 - 作った変換クラスを、ラジオボタンのバインド時のConverterに指定する。
その時のConverterParameterには、ラジオボタンばONにしたいEnumの値を設定する。
それで、変換クラスに関しては、Enum<->Boolに関しては、ほとんど定型化されている様で、WebやQAサイトに掲載されたものをそのまま使用した。
問題発覚
ここで、実際に動作させてみたところ、プログラム内からEnumのプロパティを変更しても、ラジオボタンの設定が変わらなかった。
デバッガで、Enumのプロパティのsetで確認したところ、プログラム内での設定の後、もう一回、元の値に戻すような呼び出しがあった。
よく調べたところ、ConvertBackの実装に問題があったことが分かった。
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return Enum.Parse(targetType, parameter.ToString());
}
これが問題があったもの。
原因
valueに、ラジオボタンのON/OFFの状態、つまりtrue/falseが入ってきているのだが、それを見ずに、単純にEnumの型に変換していたため。
2度目の呼び出しは、OFF状態になったラジオボタンからの呼び出しだった。
対応
一応、再度IValueConverterのヘルプを確認したところ、結果として、valueがfalseの場合、DependencyProperty.UnsetValueを返すことにした。
ヘルプの内容は次の通り。
戻り値は、変換された値で、メソッドがnullを返す場合は、有効なnull値が使用されます。
データバインディングエンジンは、バインディングターゲットからバインディングソースに値を伝播するときにこのメソッドを呼び出します。
このメソッドの実装はConvertメソッドの逆である必要があります。
今回のケースではEnum―bool変換なので、nullは返せない。その場合は、DependencyProperty.UnsetValueもしくはBinding.DoNothingということになるらしいのだが、きちんと後処理もさせるのならDependencyProperty.UnsetValueがいいということらしい。
どちらがいいかWebのほうも検索したら、結構バラバラ。海外のQAサイトでは、特別な理由がなければDependencyProperty.UnsetValueでしょ、とのこと。
一応両方試しては見たが、どちらも最終的には要望する結果にはなったのだが、ヘルプで勧められている?DependencyProperty.UnsetValueを使用した。
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
if (true.Equals(value)) {
return Enum.Parse(targetType, parameter.ToString());
}
else {
return System.Windows.DependencyProperty.UnsetValue;
}
}
最後に
EnumとBoolの一般化できるようなコードなら、System.Windows.Dataなりの中に用意してもらっていた方がよかったのに。
コメント