改进的IValueConverter——MarkupExtension或DependencyObject



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

从每一个角度出发,给你不同的力量和灵活性:

  • 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说,

  • 每个绑定通常有以下四个组件:一个绑定目标对象,目标属性,绑定类中值的路径绑定要使用的源。例如,如果的内容绑定文本框的Name属性Employee对象,你的目标对象是在TextBox中,是目标属性当Text属性时,要使用的值为名称,源对象是Employee对象。

  • 目标属性必须是一个依赖属性

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

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

假设你想做这样的事情:

<UserControl.Resources>
    <con:CaseConverter Casing="{Binding SomeProperty}"/>
</UserControl.Resources>

这不起作用,因为资源不是可视树的一部分,因此绑定将失败。虚拟分支绕过了这个小难题,使您能够执行这样的绑定。然而,像其他WPF绑定一样,它仍然依赖于目标是DependencyObject。因此,如果我只是实现IValueConverter而不扩展DependencyObject,您将无法使用虚拟分支。

现在,如果我完全诚实的话,我不确定如果我有时间的话我还会这样做。实际上,我自己从来没有使用过虚拟分支——我只是想启用这个场景。我甚至可能在我的库的未来版本中改变这一点。所以我的建议是坚持使用Object的基类(或其简单的派生类),除非你真的认为你需要虚拟分支。

相关内容

  • 没有找到相关文章

最新更新