以下の内容はhttps://shikaku-sh.hatenablog.com/entry/wpf-tips-value-converterより取得しました。


WPF IValueConverter の小ネタとテクニックの整理

WPF の IValueConverter を実装するときの考え方と小ネタ。

MarkupExtension の実装と DependancyProperty の実装

IValueConverterIMultiValueConverter でも ValueConverter はコンバーターにプロパティを実装したいときに MarkupExtension を使った実装も、DependancyProperty を使った実装も(一応)どちらでも可能です。

個人的なポイントとしては、MarkupExtension を使った実装をすると、IValueConverter のパラメータを追加する手法としてはシンプルで自然なものになります。この特徴として、XAML のスコープごとに異なる設定を持った Converter を使いやすい。柔軟なパラメータの代入が可能です。

<CheckBox IsEnabled="{Binding Sample, Converter={local:SampleConverter SampleParam=1}}" />
<CheckBox IsEnabled="{Binding Sample, Converter={local:SampleConverter SampleParam=3}}" />

ValueConverter を使った実装は、いくらか個性的な(または、トリッキーな)手法になる恐れがあり、あまり優位性はないと思いますが、ネット上にはこの設計をしているものもあります。

メリットは、引数の型を決めることができます。string 型ではなくて class や enum の値を初期設定しやすいと思います。

基本的に ValueConverter は、Binding しない。Binding したいときは、該当するパラメータを MultiBindingConverter にして引数として渡すほうがよい。

<local:SampleConverter Key="SampleConverter1" SampleParam="A" />
<!--(要:Freezable) -->
<local:SampleConverter Key="SampleConverter1" SampleParam="{Binding A}" />

パラメータがないときの実装パターン

このときは ConverterParameter で固定値の(基本的には文字列)のパラメータを代入します。

<Label Content="{Binding Text1, Converter={StaticResource NoParamConverter}, ConverterParameter=Param1}" />

MarkupExtension の実装パターン

public class SampleValueConverter : MarkupExtension, IValueConverter
{
    public string SampleParam { get; set; } = "";

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        Debug.WriteLine($"SampleParam = {SampleParam}");
        return this; // IValueConverter 自体を返す
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return SampleParam == "1";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        => throw new NotImplementedException();
}

ProvideValue の設定が IValueConverter の場合は、ちょっと違和感があると思います。他の例だとこんなのはわかりやすい。

ProvideValue を実装する意味は、コンバーター自身を拡張プロパティの書き方ができるように認めてほしいから。

<CheckBox IsEnabled="{Binding Sample, Converter={local:SampleConverter SampleParam=1}}" />

Resources に宣言するのではなくて、上記の書き方のように突然 Converter の中で SampleConverter を設定したいときは MarkupExtension が必要になる。

Resources に対して StaticResource として登録したデータに SampleParam=1 という引数の部分を書けるようにするわけではないので注意。(個人的に混同したことがある)

Freezable を使う

以下のようにして、Binding をすることもできる。(ただし、Freezable は動作がトリッキーなので注意したい)

Param の変化には対応できないので、Param のインスタンスが変わらなければ、Param の同じインスタンス内のパラメーターを追い続けることができる(はず)。

<local:ParamEx3Converter x:Key="ParamEx3Converter1" Param="{Binding Param}" />
public class ParamEx3Converter : Freezable, IValueConverter
{
    public static readonly DependencyProperty ParamProperty =
        DependencyProperty.Register(nameof(Param), typeof(string), typeof(ParamEx3Converter), new PropertyMetadata(""));

    public string Param
    {
        get => (string)GetValue(ParamProperty);
        set => SetValue(ParamProperty, value);
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return $"{value} : {Param}";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        => throw new NotImplementedException();

    protected override Freezable CreateInstanceCore()
        => new ParamEx3Converter();
}

Sample

GitHub に Converter の挙動を整理したサンプルを公開しています。

  • パラメーターなしのとき
  • MarkupExtension
  • DependencyObject
  • Freezable

最後にもう一度再掲載:

基本的に ValueConverter は、Binding しない。Binding したいときは、該当する Binding パラメータを MultiBindingConverter にして引数として渡すほうがよい。

参考




以上の内容はhttps://shikaku-sh.hatenablog.com/entry/wpf-tips-value-converterより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14