WPF:MarkupExtensionのようなコンバーター

コンバーターは、WPFのバインディングメカニズムの最も重要な機能の1つです。 UIでのバインディングソースの表示方法を制御できます。 この記事では、XAMLコードでのコンバーターの使用を少し単純化する方法を示します。



最も簡単な例を考えてみましょう。

public class DateConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { DateTime date = (DateTime)value; return date.ToShortDateString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return null; } }
      
      





すべてが単純です。入力コンバーターはDateTime型の値を受け取り、それを文字列に変換します。 逆変換は提供されません。



コンバーターは次のように使用されます。

 <Window x:Class="TestConvertorMarkup.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="clr-namespace:TestConvertorMarkup.Converters" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <converters:DateConverter x:Shared="false" x:Key="dateConverter"/> </Window.Resources> <Label Content="{Binding Path=Date, Converter={StaticResource dateConverter}}" /> </Window>
      
      





ここでも複雑なことは何もありませんが、このアプローチのマイナス面は、コンバーターごとに対応するリソースを作成する必要があることです。 そして、グローバルリソースディクショナリでこれを行うか、各XAMLファイルで使用されているすべてのコンバーター用に独自のリソースを作成する必要があります。 インターネットでいくつか検索した後、 ここで別の解決策を見つけました。



まず、コンバーター自体を変更します。



 public class NumberToStringConverterExtension: MarkupExtension, IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { DateTime date = (DateTime)value; return date.ToShortDateString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } public override object ProvideValue(IServiceProvider serviceProvider) { if (_converter == null) _converter = new NumberToStringConverterExtension(); return _converter; } private static NumberToStringConverterExtension _converter = null; }
      
      





このような変更の後、XAMLで使用するために必要なことは次のとおりです。

 <Label Content="{Binding Path=Date, Converter={converters:DateTimeToString}}" />
      
      





当然。 適切な「コンバータ」名前空間を追加することを忘れないでください。

素敵なボーナスは、入力時に利用可能なコンバーターのリストが表示されることです:



それで終わりではありませんが、可能な限り新しいコンバーターの作成を簡素化するために、基本クラスを導入します。

 public abstract class ConvertorBase<T> : MarkupExtension, IValueConverter where T : class, new() { /// <summary> /// Must be implemented in inheritor. /// </summary> public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture); /// <summary> /// Override if needed. /// </summary> public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } #region MarkupExtension members public override object ProvideValue(IServiceProvider serviceProvider) { if (_converter == null) _converter = new T(); return _converter; } private static T _converter = null; #endregion }
      
      





ここからDateConverterを継承し、その中にConvertメソッドを実装します。 最終バージョンは次のようになります。

 public class DateTimeToString : ConvertorBase<DateTimeToString> { public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { DateTime date = (DateTime)value; return date.ToShortDateString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return null; } }
      
      





XAMLコードは2番目の例と同じままです。



したがって、XAMLマークアップで単純化された構文を使用する機会があり、コンバーターコードは実質的に変更されませんでした。



サンプル付きのPSプロジェクトはこちらからダウンロードできます



All Articles