我正在尝试在WPF中创建一个隐式转换。
让我们说我们有一个枚举:
public enum MyEnum
{
A1,
B2,
C3,
D5
}
我想将ComboBox中显示的值与不同的东西交换。所以我创建了一个包装类:
public class EnumDisplay
{
public object Value { get; set; }
public String Text { get; set; }
}
我用一些实例填充一个集合,比如
new EnumDispay
{
Value = MyEnum.A1,
Text = "Foo"
}
我们通常会为这样的ComboBox创建绑定:
<ComboBox ItemsSource="{Binding WhatEver}"
SelectedValuePath="Value"
SelectedValue="{Binding Val}"/>
像魅力一样工作 - 但我想使用简化/直接前向绑定。 无转换器,无显示/值路径。就像这样简单的绑定:
<ComboBox ItemsSource="{Binding WhatEver}"
SelectedItem="{Binding Val}"/>
我尝试在TypeConverter
类
EnumDispay
属性
[TypeConverter(typeof(EnumDisplayTypeConverter))]
但它似乎只用于将我的EnumDisplay
类转换为字符串...
public class EnumDisplayTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
//never called
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
//desttype is always String
if (context != null)
{
if (context.Instance != null)
{
if (context.Instance.GetType() == typeof(EnumDisplay))
{
return true;
}
}
}
return false;
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
//never called
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
//desttype is always String
var t = value as EnumDisplay;
if (t != null)
{
return t.Value.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
仍然,我继续接收通常的WPF转换异常:
System.Windows.Data Error: 23 : Cannot convert 'bbb' from type 'EnumDisplay' to type MyEnum' with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException:...
bei System.ComponentModel.TypeConverter.GetConvertFromException(Object value)
bei System.ComponentModel.TypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
bei System.ComponentModel.EnumConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
bei MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)'
System.Windows.Data Error: 7 : ConvertBack cannot convert value 'bbb' (type 'EnumDisplay'). BindingExpression:Path=Val; DataItem='MainVM' (HashCode=30659444); target element is 'ComboBox' (Name=''); target property is 'SelectedItem' (type 'Object') NotSupportedException:'System.NotSupportedException: EnumConverter...
bei MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)
bei MS.Internal.Data.ObjectTargetConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
bei System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)'
似乎仍然使用默认EnumConverter
。我在这里缺少什么?
我创建了一个简单的转换器来将枚举转换为EnumDisplay:
public class SomeTypeConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is EnumDisplay)
{
return (value as EnumDisplay).Value;
}
return base.ConvertFrom(context, culture, value);
}
}
由于WPF使用TypeDescriptor进行转换器查找,我所要做的就是:
TypeDescriptor.AddAttributes(typeof(MyEnum), new TypeConverterAttribute(typeof(SomeTypeConverter)));
它在一个方向上完美无缺。
但如果我这样做:
ViewModel.Val = MyEnum.D5
ComboBox似乎没有选定的值(已实施ChangeNotification)。另外提供SelectedValuePath属性将解决这个问题,但这是我想要避免的!
答案 0 :(得分:1)
您应该在枚举类型中应用[TypeConverter(...)]
属性,并实施CanConvertFrom
和ConvertFrom
。对于EnumDisplay
,您可以覆盖ToString
或使用实施TypeConverter
和CanConvertTo
的{{1}}。
当WPF尝试显示ConvertTo
课程的实例时,它会检查EnumDisplay
是否有EnumDisplay
。如果是,则会使用它将TypeConverter
- 如果可能的话转换为EnumDisplay
,否则转换为UIElement
。如果转换为string
是可能的并且您已覆盖string
,那么它会调用它,否则转换将通过ToString
的{{1}}进行路由。此处仅使用EnumDisplay
和TypeConverter
。
当绑定系统尝试更新绑定的source属性时,它会检查该属性的类型是否具有CanConvertTo
。换句话说,如果ConvertTo
有TypeConverter
。如果是,则会在其上调用MyEnum
。它可能会或可能不会调用TypeConverter
,可能取决于您使用的WPF版本。只要实施两者都是安全的。
答案 1 :(得分:0)
即使它没有隐式转换您的ENUM
,您也可以使用以下EnumExtensions让思考更轻松public static string GetDescription(this Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
var attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return value.ToString();
}
public static Dictionary<T, string> EnumToDictionary<T>()
{
var enumType = typeof(T);
if (!enumType.IsEnum)
throw new ArgumentException("T must be of type System.Enum");
return Enum.GetValues(enumType)
.Cast<T>()
.ToDictionary(k => k, v => ( v as Enum ).GetDescription());
}
<强>枚举强>
using System.ComponentModel;
public enum MyEnum
{
[Description("foo1")]
A1,
[Description("foo2")]
B2,
[Description("foo3")]
C3,
[Description("foo4")]
D5
}
<强> ViewModel.cs 强>
public Dictionary<MyEnum, string> Dict
{
get { return EnumExtension.EnumToDictionary<MyEnum>(); }
}
private MyEnum _selectedValue;
public MyEnum SelectedValue
{
get { return _selectedValue; }
set
{
_selectedValue= value;
RaisePropertyChanged(() => Reg(() => SelectedValue));
}
}
<强> View.xaml 强>
<ComboBox DisplayMemberPath="Value"
SelectedValuePath="Key"
ItemsSource="{Binding Dict}"
SelectedValue="{Binding SelectedValue}"/>