改进了IValueConverter – MarkupExtension还是DependencyObject?

我在网上看到了两种不同的方法来增强IValueConverter。 其中一个从MarkupExtension扩展了ValueConverter,另一个从DependencyObject扩展。 我无法从两者延伸,所以我想知道是否有一个比另一个好?

从每个衍生出来给你不同的力量和灵活性:

  • 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:

       

    这样的代码在调试时非常方便,因为你可以编写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中,您可以直接使用它:

             

    它有什么作用? 如果超过50字符,它会截断字符串FullDescription

@crazyarabian评论说:

您的语句“从DependencyObject派生使您能够以更具表现力的方式使用某些首选项配置值转换器”并不是DependencyObject独有的,因为您可以在MarkupExtension上创建相同的MaxLength属性,从而导致 。 我认为MarkupExtension更具表现力且更简洁。

那是真实的。 但那是不可约束的; 也就是说,当你从MarkupExtension派生时,你不能这样做:

 MaxLength="{Binding TextLength}" 

但是,如果从DependencyObject派生转换器,则可以执行上述操作。 从这个意义上说,与MarkupExtension相比,它更具表现力

请注意,target属性必须是DependencyProperty才能使Binding工作。 MSDN说,

  • 每个绑定通常具有以下四个组件:绑定目标对象,目标属性,绑定源以及要使用的绑定源中的值的路径。 例如,如果要将TextBox的内容绑定到Employee对象的Name属性,则目标对象是TextBox, target属性是Text属性 ,要使用的值是Name,源对象是员工对象。

  • target属性必须是依赖属性。

因为它是我的库,你引用的是扩展DependencyObject的转换器的例子,我认为这适合解释自己。

我实际上是通过简单地实现IValueConverterObject作为我的基类开始的。 我改用扩展DependencyObject的唯一原因是允许一种技术 – 由Josh Smith开创 – 称为虚拟分支 。 你可以在这里阅读这种技术。

假设你想做这样的事情:

    

这不起作用,因为资源不是可视树的一部分,因此绑定将失败。 虚拟分支破解了这个小难题,使您能够执行这样的绑定。 但是,它仍然依赖于 – 就像任何其他WPF绑定一样 – 作为DependencyObject的目标。 因此,如果我只是在不扩展DependencyObject情况下实现IValueConverter ,则会阻止使用虚拟分支。

现在,如果我完全诚实,我不确定如果我再次有时间,我仍然会这样做。 我自己从来没有真正使用过虚拟分支 – 我只是想启用这个场景。 我甚至可以在我的库的未来版本中更改它。 所以我的建议是坚持Object的基类(或其简单的衍生物),除非你真的认为你需要虚拟分支。