RadioButtonは複数の選択肢から1つを選ぶ時によく使われるコントロール。
ただし、RadioButtonにチェックマークを付ける為のIsCheckedプロパティはbooleanなので、3つ以上の選択肢から選ばせる場合など作り込みが必要になる。
列挙型の値をRadioButtonにバインドさせる方法を考える。
WPFのBindingの仕組みでは、間にコンバータを挟んで値を変換しながらバインドする事が出来る。
以下の例では、特定の列挙型に依存しない汎用的なコンバータを作成し、複数のRadioButtonを1つのデータへバインドさせている。
列挙型をBooleanへ変換するコンバータ
public class EnumToBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var parameterString = parameter as string; if (null == parameterString) return DependencyProperty.UnsetValue; if (!Enum.IsDefined(value.GetType(), value)) return DependencyProperty.UnsetValue; var parameterValue = Enum.Parse(value.GetType(), parameterString); return parameterValue.Equals(value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var parameterString = parameter as string; if (null == parameterString) return DependencyProperty.UnsetValue; if (true.Equals(value)) return Enum.Parse(targetType, parameterString); else return DependencyProperty.UnsetValue; } }
IValueComverterインターフェースを実装したクラスの作成 (1行目)
IValueConverterインターフェースを実装する事で、バインディンク時のコンバータとして利用できるクラスを作成する事が出来る。
enumからbooleanへの変換 (3~14行目)
Convertメソッドにenumからbooleanへ変換するコードを書く。
意図しない値が入ってきた時はDependencyProperty.UnsetValueを戻り値にする。
パラメータparampeterはXAMLから渡される値で、列挙型の値を文字列で指定させる仕様。
Enum.Parseメソッドを使って文字列からenumを作成して、等しいかどうかを戻り値にする。
こうする事で、特定の列挙型に依存しない汎用的なコンバータになる。
booleanからenumへの変換 (16~26行目)
ConvertBackメソッドにbooleanからenumへ変換するコードを書く。
パラメータparampeterはXAMLから渡される値で、列挙型の値を文字列で指定させる仕様。
trueの時は、parameterの文字列からenumを作成してそれを戻り値にする。
falseの時は、DependencyProperty.UnsetValueを戻り値にする。
XAML
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApplication1" mc:Ignorable="d" Title="MainWindow" Height="150" Width="250"> <Window.Resources> <ResourceDictionary> <local:EnumToBooleanConverter x:Key="EnumToBoolean"/> </ResourceDictionary> </Window.Resources> <StackPanel Margin="20"> <RadioButton Content="タイプ1" IsChecked="{Binding Path=Sample,Mode=TwoWay,Converter={StaticResource EnumToBoolean},ConverterParameter=TYPE1,UpdateSourceTrigger=PropertyChanged}"/> <RadioButton Content="タイプ2" IsChecked="{Binding Path=Sample,Mode=TwoWay,Converter={StaticResource EnumToBoolean},ConverterParameter=TYPE2,UpdateSourceTrigger=PropertyChanged}"/> <RadioButton Content="タイプ3" IsChecked="{Binding Path=Sample,Mode=TwoWay,Converter={StaticResource EnumToBoolean},ConverterParameter=TYPE3,UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> </Window>
Resourcesへコンバータを定義 (9~13行目)
上記で作成したコンバータを利用できるようにWindow.Resourcesへ定義する。
定義したコンバータにはx:Key属性を使って名前をつけている。
RadioButtonのバインド (15~16行目)
3つのRadioButtonは全てSampleという同じ値へバインドさせている。
Converterに作成したコンバータを定義する。
ConverterParameterはコンバータのparameterへ渡される値なので、RadioButtonにチェックが付く時の列挙型の値を指定する。
更に、プロパティが更新されたら表示が更新されるようにUpdateSourceTriggerにはPropertyChangedを指定している。
ソース
public enum SampleType { TYPE1, TYPE2, TYPE3 }; public class SampleData : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string name) { if (null == this.PropertyChanged) return; this.PropertyChanged(this, new PropertyChangedEventArgs(name)); } private SampleType _Sample; public SampleType Sample { get { return _Sample; } set { _Sample = value; OnPropertyChanged("Sample"); } } } public partial class MainWindow : Window { private SampleData Data; public MainWindow() { Data = new SampleData(); Data.Sample = SampleType.TYPE1; this.DataContext = Data; InitializeComponent(); } }
列挙型を定義 (1~6行目)
サンプルとして3つの値を定義した。
バインドされるデータの定義 (12~28行目)
コントロールとデータの双方向で更新されるように、INotifyPropertyChangedインターフェースを実装したデータ構造を作成する。
INotifyPropertyChangedの使い方については以下を参照。
コメントをお書きください