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関数をすぐ実装できるのが地味に便利。
自動生成される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);
}