15

IValueConverterを強化するための2つの異なるアプローチをオンラインで見ました。それらの1つはMarkupExtensionからValueConverterを拡張し、もう1つはDependencyObjectから拡張しました。私は両方から拡張することはできないので、どちらかがもう一方よりも優れているかどうか疑問に思いますか?

4

2 に答える 2

39

それぞれから派生することで、さまざまな種類のパワーと柔軟性が得られます。

  • 以下で説明するように、派生元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 は次のようにコメントしています。

MarkupExtension で同じ MaxLength プロパティを作成できるため、「DependencyObject から派生させると、より表現力豊かな方法でいくつかの設定を使用して値コンバーターを構成できます」というステートメントは DependencyObject に限定されません<TextBlock Text="Binding Age, Converter={local:DoubleMe, MaxLength=50}}"/>。MarkupExtension はより表現力があり、冗長ではないと私は主張します。

それは本当です。しかし、それは束縛可能ではありません。つまり、から派生した場合MarkupExtension、次のことはできません。

MaxLength="{Binding TextLength}"

しかし、コンバーターを から派生さDependencyObjectせた場合は、上記を行うことができます。そういう意味では に比べて表現力MarkupExtensionがありますね。

ターゲット プロパティが動作するためにはDependencyPropertyfor でなければならないことに注意してくださいBindingMSDN によると、

  • 通常、各バインディングには、バインディング ターゲット オブジェクト、ターゲット プロパティ、バインディング ソース、および使用するバインディング ソース内の値へのパスという 4 つのコンポーネントがあります。たとえば、TextBox のコンテンツを Employee オブジェクトの Name プロパティにバインドする場合、ターゲット オブジェクトは TextBox、ターゲット プロパティは Text プロパティ、使用する値は Name、ソース オブジェクトは従業員オブジェクト。

  • ターゲット プロパティは依存関係プロパティである必要があります。

于 2011-09-16T13:25:14.113 に答える
5

拡張するコンバーターの例として引用しているのは私のライブラリーなのでDependencyObject、自分自身を説明するのにふさわしいと思います。

私は実際、基本クラスとしてを実装IValueConverterすることから始めました。Object私が拡張に切り替えた唯一の理由は、仮想分岐DependencyObjectと呼ばれる、JoshSmithによって開拓された手法を可能にすることでした。あなたはここでそのテクニックについて読むことができます。

次のようなことをしたいとします。

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

リソースはビジュアルツリーの一部ではないため、これは機能しません。そのため、バインディングは失敗します。仮想分岐はこの小さなジレンマをハックし、そのようなバインディングを実行できるようにします。ただし、他のWPFバインディングと同様に、ターゲットがであることに依然依存していDependencyObjectます。したがって、IValueConverterを拡張せずに単純に実装した場合DependencyObject、仮想ブランチを使用できなくなります。

さて、私が完全に正直であるならば、私が再び私の時間を持っていたならば、私がまだこれをするかどうかはわかりません。実際に自分で仮想ブランチを使用する必要はありませんでし。シナリオを有効にしたかっただけです。ライブラリの将来のバージョンでこれを変更する可能性もあります。Objectしたがって、仮想分岐が本当に必要だと本当に思わない限り、私のアドバイスは基本クラス(またはその単純な派生物)に固執するでしょう。

于 2011-10-05T08:18:17.190 に答える