从每个类派生出来会给你不同类型的功能和灵活性:
从MarkupExtension
派生可以让你在不把值转换器变为静态资源的情况下使用它,如下所述:
public class DoubleMe : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, /*rest of parameters*/ )
{
if ( value is int )
return (int)(value) * 2; //double it
else
return value.ToString() + value.ToString();
}
//...
}
在XAML中,您可以直接使用它,而无需创建StaticResource:<TextBlock Text="{Binding Name, Converter={local:DoubleMe}}"/>
<TextBlock Text="{Binding Age, Converter={local:DoubleMe}}"/>
当进行调试时,这段代码非常方便,因为你可以只需编写local:DebugMe
,然后就可以调试使用它的控件的DataContext。
继承自DependencyObject
,可以使你以一种更具表现力的方式配置值转换器的某些偏好,如下所述:
public class TruncateMe : DependencyObject, IValueConverter
{
public static readonly DependencyProperty MaxLengthProperty =
DependencyProperty.Register("MaxLength",
typeof(int),
typeof(TruncateMe),
new PropertyMetadata(100));
public int MaxLength
{
get { return (int) this.GetValue(MaxLengthProperty); }
set { this.SetValue(MaxLengthProperty, value); }
}
public object Convert(object value, /*rest of parameters*/ )
{
string s = value.ToString();
if ( s.Length > MaxLength)
return s.Substring(0, MaxLength) + "...";
else
return s;
}
//...
}
在 XAML 中,你可以直接使用它,例如:<TextBlock>
<TextBlock.Text>
<Binding Path="FullDescription">
<Binding.Converter>
<local:TruncateMe MaxLength="50"/>
</Binding.Converter>
</Binding>
</TextBlock.Text>
它的作用是:如果字符串FullDescription
超过50
个字符,它会将其截断!
@crazyarabian发表了评论:
你的陈述“从DependencyObject派生使您能够以更具表现力的方式配置值转换器的某些首选项”不仅适用于DependencyObject,还可以在MarkupExtension上创建相同的MaxLength属性,结果是
<TextBlock Text="Binding Age, Converter={local:DoubleMe, MaxLength=50}}"/>
。我认为MarkupExtension更具表现力且更简洁。
那是真的。但是那不可绑定;也就是说,当您从MarkupExtension
派生时,您无法做到:
MaxLength="{Binding TextLength}"
但是如果你从DependencyObject
派生出你的转换器,那么你可以做到上述操作。在这个意义上,与MarkupExtension
相比,它更加表达力强。
请注意,目标属性必须是DependencyProperty
才能使Binding
起作用。MSDN说:
每个绑定通常都包含以下四个组件:绑定目标对象、目标属性、绑定源和要使用的绑定源中的值的路径。例如,如果您想将TextBox的内容绑定到Employee对象的Name属性,则目标对象是TextBox,目标属性是Text属性,要使用的值是Name,源对象是Employee对象。
目标属性必须是依赖属性。
既然你引用我的库作为扩展DependencyObject
的转换器示例,我认为有必要解释一下。
我最初只是使用Object
作为基类来实现IValueConverter
。我改为扩展DependencyObject
的唯一原因是为了使用Josh Smith开创的一种名为虚拟分支的技术。你可以在这里阅读相关内容。
假设你想做这样的事情:
<UserControl.Resources>
<con:CaseConverter Casing="{Binding SomeProperty}"/>
</UserControl.Resources>
这样做是行不通的,因为资源不是可视树的一部分,所以绑定会失败。虚拟分支可以解决这个问题,使您能够执行此类绑定。然而,它仍然依赖于目标是一个DependencyObject
,就像任何其他WPF绑定一样。因此,如果我只实现了IValueConverter
而没有扩展DependencyObject
,您将无法使用虚拟分支。
现在,坦白地说,如果我再来一次,我不确定我还会这样做。我从未真正需要使用虚拟分支 - 我只是想启用这种情况。我甚至可能在我的库的未来版本中更改这一点。因此,我的建议是除非您真的认为需要虚拟分支,否则坚持使用Object
(或其简单派生类)作为基类。