もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f
やりたいこと
WPFで画面を作るときにコンバーターをよく使うが、都度既存のコードからコピペしていて身についた感がなかったので、テンプレートとして持っておくために下記にメモしておく。
コンバーターの作り方
今回は、MSの公式サンプルをもとに、
- DateTime型の値を、画面表示の際に日付の文字列に変換する
- 日付の文字列を、プロパティget時にDateTime型の値に変換する
というコンバーターを作ってみる。
コンバーターのクラスを作る
クラス名はDateTimeConverterのように、〇〇Conveterというようにするのが慣例っぽい。
その名前で、IValueConverterインターフェースを実装した下記のようなクラスを作る。
- Convertメソッドが「プロパティ→画面表示に反映時」の変換を記述するところ。
- ConvertBackメソッドが「画面表示→プロパティに反映時」の変換記述するところ。
publicclassDateTimeConverter:IValueConverter{// DateTimeを「yyyy/MM/dd HH:mm:ss.fff」形式の文字列に変換publicobjectConvert(objectvalue,TypetargetType,objectparameter,CultureInfoculture){DateTimedate=(DateTime)value;returndate.ToString("yyyy/MM/dd HH:mm:ss.fff");}// 文字列をDateTimeに変換publicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){stringstrValue=valueasstring;DateTimeresultDateTime;if(DateTime.TryParse(strValue,outresultDateTime)){returnresultDateTime;}returnDependencyProperty.UnsetValue;}}※個人的経験では、ほとんどの場合「プロパティ→画面表示に反映時」に変換することしかしないので、Converterメソッドだけ使ってConvertBackメソッドはほとんど使ったことがない。
そういう場合は、ConvertBackの中身は下記のようにしておけばいい。
publicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){thrownewNotImplementedException();}画面にリソースとして登録し、それを変換したいところで使う
一番の親(今回はWindow)のリソースとして、下記のようにして登録する。
<Window.Resources><converter:DateTimeConverterx:Key="DateTimeConverter"/></Window.Resources>そいつのKeyを使って、変換を行いたいコントロールにバインドしたプロパティのコンバーターとして使用する。
(今回は、ConverterParameterは別に不要だが、パラメータ渡せるということを示すために渡すだけ渡す)
<TextBoxGrid.Row="1"Grid.Column="2"Text="{Binding Dt, ElementName=root, Converter={StaticResource DateTimeConverter}, ConverterParameter=123}"/>ViewModel等に、バインドするプロパティを作成して、get/setしてみる
下記のように、画面にバインドしたプロパティに
- set(今回は
Dtに現在の日付をセットした) - get(今回は
Dtの値をゲットしてyyyyねんMMがつddにち形式で表示した)
publicDateTimeDt{get{return_dt;}set{_dt=value;OnPropertyChanged(nameof(Dt));}}// テキストボックス ← プロパティprivatevoidButton_Click(objectsender,RoutedEventArgse){// setDt=DateTime.Now;}// テキストボックス → プロパティprivatevoidButton_Click_1(objectsender,RoutedEventArgse){// getAddLog(Dt.ToString("入力した日付は、yyyyねんMMがつddにち です"));}そうすると、コンバータを通って、下記のように画面に表示される。
以上で、一通りコンバーターが使えるようになった。
コード全部
usingSystem;usingSystem.Globalization;usingSystem.Windows;usingSystem.Windows.Data;namespaceWpfApp48.converter{[ValueConversion(typeof(DateTime),typeof(string))]publicclassDateTimeConverter:IValueConverter{// DateTimeを「yyyy/MM/dd HH:mm:ss.fff」形式の文字列に変換publicobjectConvert(objectvalue,TypetargetType,objectparameter,CultureInfoculture){DateTimedate=(DateTime)value;returndate.ToString("yyyy/MM/dd HH:mm:ss.fff");}// 文字列をDateTimeに変換publicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){stringstrValue=valueasstring;DateTimeresultDateTime;if(DateTime.TryParse(strValue,outresultDateTime)){returnresultDateTime;}returnDependencyProperty.UnsetValue;}}}<Windowx:Class="WpfApp48.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp48"xmlns:converter="clr-namespace:WpfApp48.converter"mc:Ignorable="d"Title="MainWindow"Height="600"Width="800"Loaded="Window_Loaded"Name="root"><Window.Resources><converter:DateTimeConverterx:Key="DateTimeConverter"/></Window.Resources><Grid><Grid.RowDefinitions><RowDefinitionHeight="5*"/><RowDefinitionHeight="1*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><StackPanelGrid.Row="1"Grid.Column="0"><ButtonContent="1"Click="Button_Click"/><ButtonContent="2"Click="Button_Click_1"/></StackPanel><ListBoxGrid.Row="0"Grid.Column="0"Grid.ColumnSpan="2"ItemsSource="{Binding Logs, ElementName=root}"/><TextBoxGrid.Row="1"Grid.Column="2"Text="{Binding Dt, ElementName=root, Converter={StaticResource DateTimeConverter}, ConverterParameter=123}"/></Grid></Window>usingSystem;usingSystem.Collections.ObjectModel;usingSystem.ComponentModel;usingSystem.Windows;namespaceWpfApp48{publicpartialclassMainWindow:Window,INotifyPropertyChanged{#regionINotifyPropertyChangedpubliceventPropertyChangedEventHandlerPropertyChanged;protectedvoidOnPropertyChanged(stringpropertyName)=>this.PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(propertyName));#endregion#regionLogFrameworkpublicObservableCollection<string>Logs{get;set;}=newObservableCollection<string>();publicvoidAddLog(stringlog){DateTimenow=DateTime.Now;Logs.Add(now.ToString("hh:mm:ss.fff ")+log);OnPropertyChanged(nameof(Logs));}#endregionDateTime_dt=DateTime.Now;publicMainWindow()=>InitializeComponent();privatevoidWindow_Loaded(objectsender,RoutedEventArgse){}publicDateTimeDt{get{return_dt;}set{_dt=value;OnPropertyChanged(nameof(Dt));}}// テキストボックス ← プロパティprivatevoidButton_Click(objectsender,RoutedEventArgse){Dt=DateTime.Now;}// テキストボックス → プロパティprivatevoidButton_Click_1(objectsender,RoutedEventArgse){AddLog(Dt.ToString("入力した日付は、yyyyねんMMがつddにち です"));}}}参考
How to: Convert Bound Data
https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/data/how-to-convert-bound-data?view=netframeworkdesktop-4.8