C#のWPFでRadioButtonのIsCheckedに列挙型をバインドする

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の使い方については以下を参照。

WPFのバインディング その1

WPFのバインディング その2

WPFのバインディング その3