在开发过程中,经常会遇到需要将单选按钮与ViewModel中的枚举类型进行绑定的情况。许多开发者会选择为每个单选按钮创建一个单独的属性在ViewModel中,但这种做法会使得ViewModel与视图之间存在过多的依赖,同时也会使得ViewModel变得庞大,并且需要为每个属性编写额外的代码来进行枚举类型的转换。实际上,只需要为每个枚举类型提供一个属性,并且使用一个通用的转换器即可。
在处理了无数次单选按钮和ViewModel的绑定之后,决定创建一种通用的方式来处理它们。
要将枚举类型绑定到一组单选按钮的IsChecked属性,需要一个ValueConverter,因为无法直接将枚举类型绑定到bool类型。虽然可以为每个单选按钮创建一个单独的ValueConverter类,但这不是必需的,因为ValueConverter的方法有一个参数,这个参数可以在XAML中通过Binding的ConverterParameter属性来设置。每个单选按钮的IsChecked属性将绑定到ViewModel中的枚举属性,使用EnumValueConverter,并设置ConverterParameter为特定枚举的名称字符串。
public class EnumValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return false;
return value.ToString() == parameter.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || parameter == null)
return null;
var rtnValue = parameter.ToString();
try
{
object returnEnum = Enum.Parse(targetType, rtnValue);
return returnEnum;
}
catch
{
return null;
}
}
}
在示例代码中,添加了三个调试方法来帮助查找错误,但为了清晰起见,这些方法已经被移除。代码相对简单。在Convert方法中,使用ToString()方法将ViewModel中的枚举转换为字符串,然后与ConverterParameter进行比较;如果相等,则返回true。在ConvertBack方法中,使用Enum.Parse方法将ConverterParameter从控件转换为ViewModel中适当的枚举类型,如果值参数在单选按钮中被选中,则自动处理未选中状态的更改,因为单选按钮只需要处理被选中状态的更改。如果解析失败,则返回null(对于null值和参数参数,由于null对于枚举类型无效(绑定不允许无效值的更改),因此没有效果)。
将XAML绑定到属性和转换器非常简单。示例中有一个非常简单的枚举:
public enum TestEnum
{
A, B, C
}
ViewModel中的这个枚举的属性也非常简单:
public TestEnum EnumBinding
{
get { return _enumBinding; }
set
{
if (_enumBinding != value)
{
_enumBinding = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("EnumBinding"));
}
}
}
现在只需要XAML,其中包括转换器的资源定义和使用转换器和ConverterParameter的绑定定义的复选框:
<Window x:Class="GenericEnumValueConverter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GenericEnumValueConverter"
Title="Enumerator Value Converter Example"
Height="200" Width="250">
<Window.Resources>
<local:EnumValueConverter x:Key="EnumValueConverter" />
</Window.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<RadioButton Content="A" IsChecked="{Binding EnumBinding,
Converter={StaticResource EnumValueConverter},
ConverterParameter=A}" />
<RadioButton Content="B" IsChecked="{Binding EnumBinding,
Converter={StaticResource EnumValueConverter},
ConverterParameter=B}" />
<RadioButton Content="C" IsChecked="{Binding EnumBinding,
Converter={StaticResource EnumValueConverter},
ConverterParameter=C}" />
</StackPanel>
</Window>
实际示例中包括一个TextBox来确认枚举属性实际上是单选按钮的值,以及一个包含错误值的额外单选按钮,以展示当XAML中存在错误的枚举值时会发生什么(在调试过程中,按下“Bad Value”单选按钮会在输出窗口中创建一条消息)。