WPFを使う-ラジオボタンとEnum

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なりの中に用意してもらっていた方がよかったのに。

コメント

タイトルとURLをコピーしました