Enum Radio Button Binding


WPFのMVVMは好きです。他の言語で似非MVVM書いてるとなんだかなーって思う。
が、やっぱりWPFは嫌いです。

はい。EnumをBindingしたいとき。

まずおもむろにEnumの拡張を用意しましょう。このブログでも出てきたと思いますよー。

public static class EnumEx
{
    public static string StringValue(this Enum e)
    {
        var fieldInfo = e.GetType().GetField(e.ToString());
        var attribute = (StringValueAttribute)fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false).FirstOrDefault();
        return attribute == null ? null : attribute.StringValue;
    }
}


次にConverterを2つ用意しましょう。

using System;
using System.Globalization;
using System.Windows.Data;

namespace Hoge
{
    [ValueConversion(typeof(Enum), typeof(bool))]
    public class EnumToRadioButtonConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value.Equals(Enum.Parse(value.GetType(), parameter.ToString()));
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(bool)value)
                return Binding.DoNothing;
            return Enum.Parse(targetType, parameter.ToString());
        }
    }
}
using System;
using System.Globalization;
using System.Windows.Data;

namespace Hoge
{
    [ValueConversion(typeof(Enum), typeof(string))]
    public class EnumToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (Enum.Parse(value.GetType(), parameter.ToString()) as Enum).StringValue();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(bool)value)
                return Binding.DoNothing;
            return Enum.Parse(targetType, parameter.ToString());
        }
    }
}


んで、enumとViewModel。双方向は省略。INotifyPropertyChangedを実装してくだされ。

namespace Hoge
{
    public enum Gender
    {
        [StringValue("男性")]
        Male,
        [StringValue("女性")]
        Female
    }

    public sealed class HogeViewModel
    {
        public Gender Gender { get; set; }
    }
}


で、View

<Page x:Class="Hoge.SamplePage"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Hoge"
            mc:Ignorable="d" 
            d:DesignHeight="500" d:DesignWidth="300">
    <Page.DataContext>
        <local:HogeViewModel x:Name="viewModel" />
    </Page.DataContext>
    <Page.Resources>
        <local:EnumToRadioButtonConverter x:Key="EnumToRadioButton"/>
        <local:EnumToStringConverter x:Key="EnumToString"/>
    </Page.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal">
            <RadioButton GroupName="Gender"
                 Content="{Binding Gender, ConverterParameter=Male, Converter={StaticResource EnumToString}}"
                 IsChecked="{Binding Gender, ConverterParameter=Male, Converter={StaticResource EnumToRadioButton}}"/>
            <RadioButton GroupName="Gender"
                 Content="{Binding Gender, ConverterParameter=Female, Converter={StaticResource EnumToString}}"
                 IsChecked="{Binding Gender, ConverterParameter=Female, Converter={StaticResource EnumToRadioButton}}"/>
        </StackPanel>
    </Grid>
</base:BasePage>