LoginSignup
6
10

More than 1 year has passed since last update.

IValueConverterの実装は型付きのBaseを作っておくと便利

Last updated at Posted at 2018-02-28

C# 7.0から使えるようになった型スイッチを使用して、ちょっとだけ型安全なIValueConverterの実装を手軽にできるようにしてみる。

変換前後の型をつけたValueConverterBase

Convert関数

IValueConverterのConvert関数を実装する際に、switchを利用して型に一致した場合だけ型付きのConvert関数に処理を渡すようにする。配列にも対応しておくと便利。

// 継承クラスで実装する型Tから型UへのConvert関数
public abstract U Convert(T value, Type targetType, object parameter, string language);

// IValueConverterの実装
public object Convert(object value, Type targetType, object parameter, string language)
{
   switch (value)
    {
        case T t_val:
            return Convert(t_val, targetType, parameter, language);
        case IEnumerable<T> t_arr:
            return t_arr.Select(t => Convert(t, targetType, parameter,language));
        default:
            return null;
    }
}

ConvertBack関数

逆変換の関数もConvert関数と同じくswitchを利用する。

// 継承クラスで実装する型Uから型TへのConvertBack関数
public abstract T ConvertBack(U value, Type targetType, object parameter, string language);

// IValueConverterの実装
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
    switch (value)
    {
        case U u_val:
            return ConvertBack(u_val, targetType, parameter, language);
        case IEnumerable<U> u_arr:
            return u_arr.Select(u => ConvertBack(u, targetType, parameter, language));
        default:
            return null;
    }
}

ValueConverterBaseクラス全体

using System;
using System.Linq;
using System.Collections.Generic;

// TからUへの変換
public abstract class ValueConverterBase<T, U> : Windows.UI.Xaml.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        switch (value)
        {
            case T t_val:
                return Convert(t_val, targetType, parameter, language);
            case IEnumerable<T> t_arr:
                return t_arr.Select(t => Convert(t, targetType, parameter, language));
            default:
                return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        switch (value)
        {
            case U u_val:
                return ConvertBack(u_val, targetType, parameter, language);
            case IEnumerable<U> u_arr:
                return u_arr.Select(u => ConvertBack(u, targetType, parameter, language));
            default:
                return null;
        }
    }

    public abstract U Convert(T value, Type targetType, object parameter, string language);
    public abstract T ConvertBack(U value, Type targetType, object parameter, string language);
}

あと、parameterを型にしてもよいかもしれない。

使い方

BoolからVisibilityにするよくあるやつ

ヒントから「考えられる修正」で型付きのConvert関数をすぐ実装できるのが地味に便利。

boolvisibility.png

自動生成されるthrow NotImplementExceptionを削除し、型にあわせてコードを書けば簡単にConverterの中身を実装できる。

using Windows.UI.Xaml;

public class BoolVisibilityConverter : ValueConverterBase<bool, Visibility>
{
    public override Visibility Convert(bool value, Type targetType, object parameter, string language)
    {
        return value ? Visibility.Visible : Visibility.Collapsed;
    }

    public override bool ConvertBack(Visibility value, Type targetType, object parameter, string language)
    {
        return value == Visibility.Visible;
    }
}

WPFの場合

using System;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;

public abstract class ValueConverterBase<T, U> : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch (value)
        {
            case T t_val:
                return Convert(t_val, targetType, parameter, culture);
            case IEnumerable<T> t_arr:
                return t_arr.Select(t => Convert(t, targetType, parameter, culture));
            default:
                return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch (value)
        {
            case U u_val:
                return ConvertBack(u_val, targetType, parameter, culture);
            case IEnumerable<U> u_arr:
                return u_arr.Select(u => ConvertBack(u, targetType, parameter, culture));
            default:
                return null;
        }
    }

    public abstract U Convert(T value, Type targetType, object parameter, CultureInfo culture);
    public abstract T ConvertBack(U value, Type targetType, object parameter, CultureInfo culture);
}
6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10