65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WPF 中使用 TypeConverter 进行绑定

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (15投票s)

2012年8月20日

CPOL

4分钟阅读

viewsIcon

58775

downloadIcon

721

本文将向您展示如何实现一个类,该类将为另一个类提供类型转换。 在这种特殊情况下,将提供与字符串之间的转换。

引言

基本上,这个例子的产生是因为需要将分隔列表转换为集合。在我正在开发的应用程序中,我使用TypeConverter类,使用反射将值从字符串转换为特定类型。我可以定义一个具有适当类型的类,然后获取字符串值并创建该类的新实例。因此,我熟悉TypeConverter,但从未实现过TypeConverter。从分隔列表创建一个用于集合的TypeConverter是有意义的。然后我想:我可以使用它在 WPF 中绑定到Text属性和ItemsSource属性吗?事实证明你可以。

标题表明本文专门针对在 WPF 中绑定到对象,但实际上是关于为类实现TypeConverter。本文将向您展示如何实现一个class,该类将为另一个类提供类型转换。在这种特殊情况下,我们将提供与字符串之间的转换。在 WPF 中,TypeConverter可用于降低在ViewModel中将自定义对象连接到View的复杂性。

TypeConverter

TypeConverter用于在数据类型之间转换值,并通过提供文本到值的转换来帮助设计时的属性配置。它使用InstanceDescriptorSystem.Reflection来提供在运行时初始化属性所需的信息。大多数本机类型都有关联的TypeConverter。默认类型转换器位于System.ComponentModel命名空间中,并命名为TypeConverterNameConverter。WPF 和 Silverlight 在绑定中广泛使用TypeConverter

要定义一个TypeConverter以支持特定类的绑定转换,您必须创建一个继承自TypeConverterclass,并覆盖ConvertToConvertFrom以及相应的CanConvertToCanConvertFrom

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);
    }
}

如果您尝试删除CanConvertToCanConvertFrom,您将看到绑定将不再起作用。

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属性进行修饰,该属性提供有关为该类提供TypeConverterclass的信息。 这提供了魔力。

现在我们有了一个可以接受string并可以将其转换为列表的类,并且可以同时绑定到期望string对象列表的DependencyPropertystring对象。 我创建的用于演示使用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 中使用并绑定到IEnumerablestring的类,这在以后的某个项目中可能会变得有用。 但是,这个概念在我的当前应用程序中非常有用。 我可以看到在某些情况下,TypeConverter可以简化编码,以支持将自定义对象绑定到 WPF 控件,而无需在ViewModel中添加不必要的转换。 我认为TypeConverter的灵活性是微软为开发人员社区提供的工具质量的另一个标志。

© . All rights reserved.