C# 带纯绑定的Impicit转换
我试图在WPF中创建隐式强制转换 假设我们有一个枚举:C# 带纯绑定的Impicit转换,c#,wpf,casting,C#,Wpf,Casting,我试图在WPF中创建隐式强制转换 假设我们有一个枚举: public enum MyEnum { A1, B2, C3, D5 } 我想用不同的东西交换组合框中显示的值。因此,我创建了一个包装器类: public class EnumDisplay { public object Value { get; set; } public String Text { get; set; } } 我使用以下实例填充集合: new EnumDispay
public enum MyEnum
{
A1,
B2,
C3,
D5
}
我想用不同的东西交换组合框中显示的值。因此,我创建了一个包装器类:
public class EnumDisplay
{
public object Value { get; set; }
public String Text { get; set; }
}
我使用以下实例填充集合:
new EnumDispay
{
Value = MyEnum.A1,
Text = "Foo"
}
我们通常为这样的组合框创建绑定:
<ComboBox ItemsSource="{Binding WhatEver}"
SelectedValuePath="Value"
SelectedValue="{Binding Val}"/>
<ComboBox ItemsSource="{Binding WhatEver}"
SelectedItem="{Binding Val}"/>
ViewModel.Val = MyEnum.D5
但它似乎只用于将我的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
。我错过了什么
更新
我创建了一个简单的转换器,用于将枚举强制转换为枚举显示:
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)));
它在一个方向上工作得非常好
但如果我这样做:
<ComboBox ItemsSource="{Binding WhatEver}"
SelectedValuePath="Value"
SelectedValue="{Binding Val}"/>
<ComboBox ItemsSource="{Binding WhatEver}"
SelectedItem="{Binding Val}"/>
ViewModel.Val = MyEnum.D5
组合框似乎不再具有所选值(实现了ChangeNotification)。同时提供SelectedValuePath属性将解决这个问题,但这是我想要避免的 您应该对枚举类型应用
[TypeConverter(…)]
属性,并实现CanConvertFrom
和ConvertFrom
。对于EnumDisplay
,您可以覆盖ToString
,或者使用实现CanConvertTo
和ConvertTo
的TypeConverter
当WPF试图显示EnumDisplay
类的实例时,它将检查EnumDisplay
是否有TypeConverter
。如果是,它将使用它将枚举显示
-如果可能,转换为ui元素
,否则转换为字符串
。如果可以转换为字符串
,并且您已经覆盖了到字符串
,那么它将调用该字符串,否则转换将通过枚举显示
的类型转换器
进行。此处仅使用CanConvertTo
和ConvertTo
但是,当绑定系统尝试更新绑定的源属性时,它会检查该属性的类型是否具有
TypeConverter
。换句话说,如果MyEnum
有一个TypeConverter
。如果它这样做了,它将对其调用ConvertFrom
。它可能会调用,也可能不会调用CanConvertFrom
,这可能取决于您使用的WPF版本。为了安全起见,只需实现这两者。您可以使用以下EnumExtensions使思考更容易,即使它不会隐式强制转换您的ENUM
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());
}
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));
}
}
公共字典Dict
{
获取{返回EnumExtension.EnumToDictionary();}
}
私有MyEnum _selectedValue;
公共MyEnum SelectedValue
{
获取{return\u selectedValue;}
设置
{
_selectedValue=值;
RaisePropertyChanged(()=>Reg(()=>SelectedValue));
}
}
View.xaml
<ComboBox DisplayMemberPath="Value"
SelectedValuePath="Key"
ItemsSource="{Binding Dict}"
SelectedValue="{Binding SelectedValue}"/>
我猜覆盖EnumDisplay的ToString()不是一个选项?欢迎来到StackOverflow!请看,其中的共识是“不,他们不应该”。@KroaX这不允许将枚举绑定到项本身。当这些属性正是针对这种情况时,您将很难避免使用SelectedValue[Path]
。我认为这对于那些将来维护您的代码的人来说是不值得的。使用这个EnumDisplay
类,您想要实现什么?如果您只想在直接绑定原始枚举值的同时更改显示文本,那么可以通过编程为每个枚举类型生成一个DataTemplate
,并在运行时将其注入应用程序的资源。(不检查是否可以进行转换)为什么会有CanConvertFrom
,它有什么合法性。。。根据:重写此方法以提供您自己的转换要求。。。?是的,有一个CanConvertFrom
方法,但WPF似乎没有使用它。我怀疑,在CanConvertFrom
中尝试并返回false
后,现在绑定不再工作了…:/奇怪,那样做对我没有任何影响。我想这取决于WPF版本1使用的是什么?无论如何,我会更新我的答案。在这里运行.NET4。。。你的版本是什么?