改进了IValueConverter - MarkupExtension还是DependencyObject?

mic*_*ael 13 c# wpf markup-extensions dependencyobject ivalueconverter

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

Naw*_*waz 37

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

  • 派生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();
       }
      //...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在XAML中,您可以直接使用它而无需创建StaticResource:

    <TextBlock Text="{Binding Name, Converter={local:DoubleMe}}"/>
    <TextBlock Text="{Binding Age, Converter={local:DoubleMe}}"/>
    
    Run Code Online (Sandbox Code Playgroud)

    这样的代码在调试时非常方便,因为您可以编写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;
         }
         //...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在XAML中,您可以直接使用它:

    <TextBlock>
       <TextBlock.Text>
           <Binding Path="FullDescription">
               <Binding.Converter>
                 <local:TruncateMe MaxLength="50"/>
               </Binding.Converter>
           </Binding>
       </TextBlock.Text> 
    
    Run Code Online (Sandbox Code Playgroud)

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

@crazyarabian评论说:

您的语句"从DependencyObject派生使您能够以更具表现力的方式使用某些首选项配置值转换器"并不是DependencyObject所独有的,因为您可以在MarkupExtension上创建相同的MaxLength属性<TextBlock Text="Binding Age, Converter={local:DoubleMe, MaxLength=50}}"/>.我认为MarkupExtension更具表现力和更简洁.

那是真实的.但那是不可约束的; 也就是说,当你从中衍生出来时MarkupExtension,你就做不到:

MaxLength="{Binding TextLength}"
Run Code Online (Sandbox Code Playgroud)

但是,如果您从中获得转换器DependencyObject,那么您可以执行上述操作.从这个意义上说,它比较具有表现MarkupExtension.

请注意,target属性必须是DependencyPropertyfor Binding才能工作.MSDN说,

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

  • target属性必须是依赖项属性.

  • 实际上,我扩展DependencyObject的原因是因为它允许您使用虚拟分支,以便您可以*绑定转换器*的属性.所述示例将不起作用,因为转换器不是可视树的一部分,无论是定义为资源还是内联.在这里阅读虚拟分支:http://www.codeproject.com/KB/WPF/AttachingVirtualBranches.aspx (2认同)

Ken*_*art 5

由于它是我的库,您引用作为扩展转换器的示例DependencyObject,我认为它适合解释我自己。

我实际上是通过简单地将IValueConverterwithObject作为我的基类来开始的。我转向扩展的唯一原因DependencyObject是允许使用一种技术——由 Josh Smith 开创——称为虚拟分支。您可以在此处阅读有关该技术的信息

假设你想做这样的事情:

<UserControl.Resources>
    <con:CaseConverter Casing="{Binding SomeProperty}"/>
</UserControl.Resources>
Run Code Online (Sandbox Code Playgroud)

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

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