我创建了一个 IValueConverter,它支持直接绑定到枚举,无需代码隐藏或辅助类。它只有两个限制:
- 每个源属性都必须使用一个转换器实例。如果模型包含更多相同枚举类型的属性,则每个属性都需要使用单独的转换器实例。这可以通过在 XAML 中实例化转换器来完成。
- 当枚举类型是标志枚举时,它必须是整数。
该解决方案基于经验事实,即在 ConvertBack 之前始终先有一个 Convert。如果 ConvertBack 更改了值,则始终存在 Convert。这仅在模型上正确实施 INotifyPropertyChanged 时才有效。因此,在两次调用之间,最后一个已知值可以存储在转换器中并在 ConvertBack 方法中使用。
转换器实例应该获取枚举的类型以及它是否是标志枚举。
<EnumToCheckedConverter x:Key="InstanceName" Type="{x:Type MyEnum}" Flags="True" />
然后可以使用此转换器绑定复选框。
<CheckBox Content="ValueText" IsChecked="{Binding Source, Converter={StaticResource InstanceName}, ConverterParameter=Value}"/>
单选按钮可以使用具有 Flags="False" 的实例通过相同的机制绑定
转换器的源代码
public class EnumToCheckedConverter : IValueConverter
{
public Type Type { get; set; }
public int? LastValue { get; private set; }
public bool Flags { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.GetType() == Type)
{
try
{
var parameterValue = Enum.Parse(Type, parameter as string);
if (Flags == true)
{
var intParameter = (int)parameterValue;
var intValue = (int)value;
LastValue = intValue;
return (intValue & intParameter) == intParameter;
}
else
{
return Equals(parameterValue, value);
}
}
catch (ArgumentNullException)
{
return false;
}
catch (ArgumentException)
{
throw new NotSupportedException();
}
}
else if (value == null)
{
return false;
}
throw new NotSupportedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value is bool check)
{
if (check)
{
try
{
if (Flags == true && LastValue.HasValue)
{
var parameterValue = Enum.Parse(Type, parameter as string);
var intParameter = (int)parameterValue;
return Enum.ToObject(Type, LastValue | intParameter);
}
else
{
return Enum.Parse(Type, parameter as string);
}
}
catch (ArgumentNullException)
{
return Binding.DoNothing;
}
catch (ArgumentException)
{
return Binding.DoNothing;
}
}
else
{
try
{
if (Flags == true && LastValue.HasValue)
{
var parameterValue = Enum.Parse(Type, parameter as string);
var intParameter = (int)parameterValue;
return Enum.ToObject(Type, LastValue ^ intParameter);
}
else
{
return Binding.DoNothing;
}
}
catch (ArgumentNullException)
{
return Binding.DoNothing;
}
catch (ArgumentException)
{
return Binding.DoNothing;
}
}
}
throw new NotSupportedException();
}
}