[WPF] Bindign用のConverterの書き方

普通の書き方

だいたいConverterの使い方として説明されるのがこんな感じだと思います。

namespace Namespace.Converters {
	public class CustomConverter: IValueConverter {
		public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {	
			// ここに処理を書く
			throw new NotImplementedException();
		}

		public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
			// ここに処理を書く
			throw new NotImplementedException();
		}
	}
}

 

Namespaceとかは適当
<Window xmlns:convert="clr-namespace:Namespace.Converters">
    <Window.Resources>
        <convert:CustomConverter x:Key="CustomConverter"/>
    </Window.Resources>

    <TextBlock Text="{Binding value, Converter={StaticResource CustomConverter}}"/>
</Window>

はい、Resourcesにいちいち入れておくのめんどくさいですね。

直接書く

直接書いてやりましょう。

<Window xmlns:convert="clr-namespace:Namespace.Converters">
	<TextBlock>
		<TextBlock.Text>
			<Binding Path="value">
				<Binding.Converter>
					<convert:CustomConverter/>
				</Binding.Converter>
			</Binding>
		</TextBlock.Text>
	</TextBlock>
</Window>

XAML長すぎでしょ・・・


Staticインスタンスを作っておく

XAML長すぎ問題がなんとかならないかと探していたところ、”Static作っとけばいいじゃん”みたいな書き込みを見つけました。

public class CustomConverter: IValueConverter {

	// Staticのインスタンスを作っちゃう
	private static CustomConverter _instance = new CustomConverter();
	public static CustomConverter Instance { get { return _instance; } }

	public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
		// ここに処理を書く
		throw new NotImplementedException();
	}


	public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
		// ここに処理を書く
		throw new NotImplementedException();
	}
}

呼び出すときはこんな感じ

<Window xmlns:convert="clr-namespace:Namespace.Converters">
    <TextBlock Text="{Binding value, Converter={x:Static convert:CustomConverter.Instance}}"/>
</Window>

便利になりました。
ただ、Template内で使用するとデザイナーがエラー表示をだします。(VS2013)
(リソースを解決できません みたいなエラー)
コンパイルもできるし、実行も問題ないんですけどね・・・


MarkupExtensionを使う

さらに、MarkupExtension を継承しておけばStaticすらいらなくなります。

public class CustomConverter: MarkupExtension, IValueConverter {

	public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
		// ここに処理を書く
		throw new NotImplementedException();
	}

	public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
		// ここに処理を書く
		throw new NotImplementedException();
	}

	public override object ProvideValue( IServiceProvider serviceProvider ) {
		return this;
	}
}
<Window xmlns:convert="clr-namespace:Namespace.Converters">
    <TextBlock Text="{Binding value, Converter={convert:CustomConverter}}"/>
</Window>

😃😃😃😃😃😃😃😃😃

こういうテクニックはなかなか見つからないですね。

参考:
WPF:Converterを使うとき、xamlのResource内で宣言をしたくないときの書き方 - RunningCSharp
WPF: How to use converters without creating static resources

[C#][WPF]マークアップ拡張の作り方



引数をつける

引数付けれるんか!!!

public class CustomConverter: MarkupExtension, IValueConverter {

	public CustomConverter( object obj, object value ){
		this.obj = obj;
		this.value = value;
	}
	object obj;
	object value;

	public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
		// ここに処理を書く
		throw new NotImplementedException();
	}

	public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
		// ここに処理を書く
		throw new NotImplementedException();
	}

	public override object ProvideValue( IServiceProvider serviceProvider ) {
		return this;
	}
}
<Window xmlns:convert="clr-namespace:namespace.Converters">
    <TextBlock Text="{Binding value, Converter={convert:CustomConverter "引数1", "引数2"}}"/>
</Window>

参考:
A Comparable DataTrigger – Data See, Data Do