概要
WPFでよく使用するConveterクラスについて、説明とサンプルコードを簡単にまとめました。
Converterクラスとは
Converterクラスは、ViewとViewModel間で異なる型のデータを、互換性のある形式に変換する役割を果たします。たとえば、ViewModelのBool型のデータを、Viewに合わせてVisibility型に変換するConverterがあるとします。その場合、ViewModelのとあるbool型のデータがtrueなら、Viewのとあるコントロールを表示、falseならとあるコントロールを非表示、という実装ができます。
他にも、ViewModelのBool型のデータを、ViewのBrushes型 (色) に変換するConverterなら、bool型の値に合わせて、Viewのコントロールの色を変更できたりします。
作成方法
Converterクラスを作る際は、標準ライブラリPresentationFramework.dllの名前空間System.Windows.Dataにある、インターフェースIValueConverterをもつのが一般的です。Converterクラス内にはConvertメソッドとConvertBackメソッドを実装します。ConvertメソッドはViewModelのプロパティからViewへの変換を記述し、ConvertBackメソッドはViewからViewModelのプロパティへの変換を記述します。
ただConvertBackメソッドは使用しない場合も多いので、
その場合はthrow new NotImplementedException();等を記述しておきます。
サンプルコード
以下に、いくつかのConverterクラスのサンプルコードをまとめました。
- 1. ViewModelのbool値をViewのVisibilityに変換する
- 2. ViewModelのbool値をViewのstringに変換する
- 3. ConverterParameterの使用例
- 4. ConvertBackの使用例
1. ViewModelのbool値をViewのVisibilityに変換する
ViewModelのとあるプロパティのbool値がtrueのときはVisible、falseのときはCollapsedに変換するクラスです。
Converter
namespace Hoge.Converters
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
if (value == null || (bool)value == false)
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
}
catch (Exception)
{
// エラーのためログ出力
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
呼出し方
View
<UserControl
x:Class="Hoge.Views.SampleView"
xmlns:converter="Hoge.Converters">
<UserControl.Resources>
<ResourceDictionary>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button
Content="サンプルボタン"
Visibility="{Binding IsButtonVisible, Converter={StaticResource BoolToVisibilityConverter}}" />
</Grid>
</UserControl>
ViewModel
ViewModelの以下のプロパティがConverterを通して、viewに適用されます。
public bool IsButtonVisible { get; set; }
2. ViewModelのbool値をViewのstringに変換する
ViewModelのとあるプロパティのbool値がtrueのときはふがふが、falseのときはほげほげという文字列に変換するクラスです。
Converter
namespace Hoge.Converters
{
public class BoolToTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
if (value == null || (bool)value == false)
{
return "ほげほげ";
}
else
{
return "ふがふが";
}
}
catch (Exception)
{
// エラーのためログ出力
return "ぴよぴよ";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
呼出し方
View
<UserControl
x:Class="Hoge.Views.SampleView"
xmlns:converter="Hoge.Converters">
<UserControl.Resources>
<ResourceDictionary>
<converter:BoolToTextConverter x:Key="BoolToTextConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button
Content="{Binding isHogeFugaPiyo, Converter={StaticResource BoolToTextConverter}}"
Visibility="Visible" />
</Grid>
</UserControl>
ViewModel
public bool isHogeFugaPiyo { get; set; }
3. ConverterParameterの使用例
xaml側でConverterParameterを使用して、Converterクラスのメソッドにパラメータを設定することもできます。下の例では、Convertクラスの引数parameterにinverseの文字があると、VisibilityとCollapsedが逆となるよう実装しています。
Converter
namespace Hoge.Converters
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
bool result;
if (value == null || (bool)value == false)
{
result = false;
}
else
{
result = true;
}
if (parameter?.ToString().ToLower() == "inverse")
{
return result ? Visibility.Collapsed : Visibility.Visible;
}
else
{
return result ? Visibility.Visible: Visibility.Collapsed;
}
}
catch (Exception)
{
// エラーのためログ出力
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
呼出し方
View
VisibilityにConverterParameter=inverseを記載しています。
<UserControl
x:Class="Hoge.Views.SampleView"
xmlns:converter="Hoge.Converters">
<UserControl.Resources>
<ResourceDictionary>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button
Content="サンプルボタン"
Visibility="{Binding IsButtonVisible, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=inverse}" />
</Grid>
</UserControl>
xamlでこのようにConverterParameterを指定すると、ConvertBackメソッドの引数parameterにも同じようにConverterParameterで指定した文字 (ここではinverse) が入ってきます。
ViewModel
public bool IsButtonVisible { get; set; }
4. ConvertBackの使用例
このサンプルではConvertBackも実装しています。
ConvertメソッドでViewModelのEmum値をstringに変換して、ConvertBackメソッドでViewのstringをViewModelのEnum値に変換しています。
ViewModelのSampleプロパティの値をConvertメソッドを使用してViewの表示値に変換するのは今までのサンプルと同じ動きです。
今回はそれに加えて、ViewのTextBoxに値が入力されLostFocusされた際に、ConvertBackメソッドを通して、ViewModelのSampleプロパティに適切な値が入ります。
namespace Hoge.Converters
{
public class SampleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return "";
var sample = (SampleEnum)Enum.Parse(typeof(SampleEnum), value.ToString());
switch (sample)
{
case SampleEnum.Hoge:
return "ほげ";
case SampleEnum.Fuga:
return "ふが";
case SampleEnum.Piyo:
return "ぴよ";
default:
// エラー処理
return "";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string sampleText = (string)value;
switch (sampleText)
{
case "ほげ":
return SampleEnum.Hoge;
case "ふが":
return SampleEnum.Fuga;
case "ぴよ":
return SampleEnum.Piyo;
default:
// エラー処理
return null;
}
}
}
}
呼出し方
View
<UserControl
x:Class="Hoge.Views.SampleView"
xmlns:converter="Hoge.Converters">
<UserControl.Resources>
<ResourceDictionary>
<converter:SampleConverter x:Key="SampleConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<TextBox Width="100" Text="{Binding Sample, Converter={StaticResource SampleConverter}" />
</Grid>
</UserControl>
ViewのTextBoxのLostFocus時にConvertBackメソッドが走るのは、
TextBoxのUpdateSourceTriggerのデフォルト値がUpdateSourceTrigger=LostFocusだからです。
例えばここで以下のようにUpdateSourceTrigger=PropertyChangedを指定すると、テキストボックスに文字が入力されたり、一文字消去されるたびに、ViewModelのプロパティも変更されるので、そのたびにConvertBackメソッドも走ります。
<TextBox Width="100" Text="{Binding Sample, Converter={StaticResource SampleConverter}, UpdateSourceTrigger=PropertyChanged}" />
ViewModel
public Class SampleClass
{
public enum SampleEnum
{
Hoge,
Fuga,
Piyo
}
public SampleEnum Sample { get; set; }
}
おわりに
Converterクラスは使い方によっては色々とバインディングの幅が広がりそうと感じました。