在 WPF 中使用 TypeConverter 进行绑定






4.91/5 (15投票s)
本文将向您展示如何实现一个类,该类将为另一个类提供类型转换。 在这种特殊情况下,将提供与字符串之间的转换。
引言
基本上,这个例子的产生是因为需要将分隔列表转换为集合。在我正在开发的应用程序中,我使用TypeConverter
类,使用反射将值从字符串转换为特定类型。我可以定义一个具有适当类型的类,然后获取字符串值并创建该类的新实例。因此,我熟悉TypeConverter
,但从未实现过TypeConverter
。从分隔列表创建一个用于集合的TypeConverter
是有意义的。然后我想:我可以使用它在 WPF 中绑定到Text
属性和ItemsSource
属性吗?事实证明你可以。
标题表明本文专门针对在 WPF 中绑定到对象,但实际上是关于为类实现TypeConverter
。本文将向您展示如何实现一个class
,该类将为另一个类提供类型转换。在这种特殊情况下,我们将提供与字符串之间的转换。在 WPF 中,TypeConverter
可用于降低在ViewModel
中将自定义对象连接到View
的复杂性。
TypeConverter
TypeConverter
用于在数据类型之间转换值,并通过提供文本到值的转换来帮助设计时的属性配置。它使用InstanceDescriptor
和System.Reflection
来提供在运行时初始化属性所需的信息。大多数本机类型都有关联的TypeConverter
。默认类型转换器位于System.ComponentModel
命名空间中,并命名为TypeConverterNameConverter
。WPF 和 Silverlight 在绑定中广泛使用TypeConverter
。
要定义一个TypeConverter
以支持特定类的绑定转换,您必须创建一个继承自TypeConverter
的class
,并覆盖ConvertTo
或ConvertFrom
以及相应的CanConvertTo
和CanConvertFrom
public class StringListTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value)
{
return new StringList((string)value);
}
public override bool CanConvertTo(ITypeDescriptorContext context,
Type destinationType)
{
return destinationType == typeof(string);
}
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type destinationType)
{
return value == null ? null : string.Join(", ", (StringList)value);
}
}
如果您尝试删除CanConvertTo
和CanConvertFrom
,您将看到绑定将不再起作用。
TypeConverter
类中可以覆盖很多其他属性,但只有这四个对于绑定很重要。TypeConverter
也用于拖放操作,这可能就是为什么需要这些方法的原因。显然,如果您不需要支持双向绑定,则无需覆盖和实现相应的方法。
我正在为此TypeConverter
编写的类旨在获取一个字符串,该字符串将获取逗号或分号分隔的列表,并将其转换为字符串列表。在这种情况下,目标是IEnumerable<string>
[TypeConverter(typeof(StringListTypeConverter))]
class StringList : IEnumerable<string>
{
private readonly IEnumerable<string> _enumerable;
private readonly string _original;
public StringList(string value)
{
_original = value;
if (!string.IsNullOrEmpty(value))
{
_enumerable = value.Split(",;".ToCharArray()).
Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => i.Trim());
}
}
protected StringList(IEnumerable<string> value)
{
_enumerable = value;
_original = string.Join(", ", value);
}
public StringList() { }
public IEnumerator<string> GetEnumerator()
{
return _enumerable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
public override string ToString()
{
return _original;
}
}
您会注意到,该类使用TypeConverter
属性进行修饰,该属性提供有关为该类提供TypeConverter
的class
的信息。 这提供了魔力。
现在我们有了一个可以接受string
并可以将其转换为列表的类,并且可以同时绑定到期望string
对象列表的DependencyProperty
和string
对象。 我创建的用于演示使用TypeConverter
的简单示例的 XAML 如下
<Window x:Class="TypeConverterExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TypeConverterExample"
Title="TypeConverter Binding Example"
Height="250"
Width="375">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Text="{Binding Source}"
/>
<ListBox Grid.Row="1"
ItemsSource="{Binding Source, Mode=TwoWay}"
/>
</Grid>
</Window>
上面的 XAML 实际上是从代码中简化的。 运行时并在文本框中输入列表后,将出现以下内容
直接使用 TypeConverter
直接使用TypeConverter
只需要一点代码,该代码用于使用TypeDescriptor
类的GetConverter
方法查找与类关联的TypeConverter
TypeConverter converter = TypeDescriptor.GetConverter(targetType);
string convertedValue = converter.ConvertFrom(value);
此代码将转换为TypeConverter
的目标。 请注意,使用的签名与编码的签名不同,后者的签名是ConvertTo(ITypeDescriptorContext, CultureInfo, object, Type)
。 这是因为父TypeConverter
类具有另一个带有单个参数的签名,并调用重写的TypeConverter
方法。 在 WPF 中,我已经在IValueConverter
中使用了TypeConverter
。
摘要
我真的不需要一个可以在 WPF 中使用并绑定到IEnumerable
和string
的类,这在以后的某个项目中可能会变得有用。 但是,这个概念在我的当前应用程序中非常有用。 我可以看到在某些情况下,TypeConverter
可以简化编码,以支持将自定义对象绑定到 WPF 控件,而无需在ViewModel
中添加不必要的转换。 我认为TypeConverter
的灵活性是微软为开发人员社区提供的工具质量的另一个标志。