IValueConverterを強化するための2つの異なるアプローチをオンラインで見ました。それらの1つはMarkupExtensionからValueConverterを拡張し、もう1つはDependencyObjectから拡張しました。私は両方から拡張することはできないので、どちらかがもう一方よりも優れているかどうか疑問に思いますか?
2 に答える
それぞれから派生することで、さまざまな種類のパワーと柔軟性が得られます。
以下で説明するように、派生元
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
がありますね。
ターゲット プロパティが動作するためにはDependencyProperty
for でなければならないことに注意してくださいBinding
。MSDN によると、
通常、各バインディングには、バインディング ターゲット オブジェクト、ターゲット プロパティ、バインディング ソース、および使用するバインディング ソース内の値へのパスという 4 つのコンポーネントがあります。たとえば、TextBox のコンテンツを Employee オブジェクトの Name プロパティにバインドする場合、ターゲット オブジェクトは TextBox、ターゲット プロパティは Text プロパティ、使用する値は Name、ソース オブジェクトは従業員オブジェクト。
ターゲット プロパティは依存関係プロパティである必要があります。
拡張するコンバーターの例として引用しているのは私のライブラリーなのでDependencyObject
、自分自身を説明するのにふさわしいと思います。
私は実際、基本クラスとしてを実装IValueConverter
することから始めました。Object
私が拡張に切り替えた唯一の理由は、仮想分岐DependencyObject
と呼ばれる、JoshSmithによって開拓された手法を可能にすることでした。あなたはここでそのテクニックについて読むことができます。
次のようなことをしたいとします。
<UserControl.Resources>
<con:CaseConverter Casing="{Binding SomeProperty}"/>
</UserControl.Resources>
リソースはビジュアルツリーの一部ではないため、これは機能しません。そのため、バインディングは失敗します。仮想分岐はこの小さなジレンマをハックし、そのようなバインディングを実行できるようにします。ただし、他のWPFバインディングと同様に、ターゲットがであることに依然依存していDependencyObject
ます。したがって、IValueConverter
を拡張せずに単純に実装した場合DependencyObject
、仮想ブランチを使用できなくなります。
さて、私が完全に正直であるならば、私が再び私の時間を持っていたならば、私がまだこれをするかどうかはわかりません。実際に自分で仮想ブランチを使用する必要はありませんでした。シナリオを有効にしたかっただけです。ライブラリの将来のバージョンでこれを変更する可能性もあります。Object
したがって、仮想分岐が本当に必要だと本当に思わない限り、私のアドバイスは基本クラス(またはその単純な派生物)に固執するでしょう。