WPF绑定Enum到RadioButton

发布时间 2023-08-21 10:38:30作者: xhubobo

将枚举型的数据类型绑定到单选按钮的IsChecked属性中,可以避免定义多个bool类型与之进行绑定,尤其是枚举类型较多时候,对bool对象的维护会更加复杂。

1、定义枚举类型及值转换器

internal enum Gender
{
    [Description("")] Male,
    [Description("")] Female,
    [Description("未知")] Unknown
}
[ValueConversion(typeof(Gender), typeof(bool?))]
public class Gender2IsCheckedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool?))
        {
            throw new InvalidOperationException("The target must be a bool");
        }

        if (value == null || parameter == null)
        {
            throw new ArgumentNullException();
        }

        if (!Enum.IsDefined(typeof(Gender), value))
        {
            throw new InvalidOperationException("The value must be a Gender");
        }

        if (!Enum.IsDefined(typeof(Gender), parameter))
        {
            throw new InvalidOperationException("The parameter must be a Gender");
        }

        return (Gender)value == (Gender)parameter;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(Gender))
        {
            throw new InvalidOperationException("The target must be a Gender");
        }

        if (parameter == null || !Enum.IsDefined(typeof(Gender), parameter))
        {
            throw new InvalidOperationException("The parameter must be a Gender");
        }

        if (value is not bool isChecked)
        {
            throw new InvalidOperationException("The value must be a bool");
        }

        return isChecked ? (Gender)parameter : Binding.DoNothing;
    }
}

2、定义RadioButton控件,并进行绑定

<Window x:Class="WpfDeveloping.Views.RadioSampleWindow"
        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:valueConverters="clr-namespace:WpfDeveloping.ValueConverters"
        xmlns:models="clr-namespace:WpfDeveloping.Models"
        mc:Ignorable="d"
        Title="RadioSampleWindow"
        WindowStartupLocation="CenterScreen"
        Height="180" Width="320">
    <Window.Resources>
        <valueConverters:Gender2IsCheckedConverter x:Key="GenderConverter"/>
        <Style x:Key="MyRadioButton" TargetType="RadioButton">
            <Setter Property="Height" Value="30"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Margin" Value="10,0,0,0"/>
        </Style>
    </Window.Resources>
    <StackPanel Orientation="Vertical">
        <RadioButton Content="" Style="{StaticResource MyRadioButton}"
                     IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter={x:Static models:Gender.Male}}"/>
        <RadioButton Content="" Style="{StaticResource MyRadioButton}"
                     IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter={x:Static models:Gender.Female}}"/>
        <RadioButton Content="未知" Style="{StaticResource MyRadioButton}"
                     IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter={x:Static models:Gender.Unknown}}"/>
    </StackPanel>
</Window>

3、在ViewModel中定义枚举对象

internal class RadioSampleWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Gender Gender
    {
        get => _gender;
        set
        {
            if (_gender != value)
            {
                _gender = value;
                OnPropertyChanged();
                Debug.WriteLine($"Current gender: {value}");
            }
        }
    }

    private Gender _gender = Gender.Unknown;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

4、运行截图