バインディングの値コンバーター
.NET Multi-platform App UI (.NET MAUI) データ バインディングでは通常、ソース プロパティからターゲット プロパティへ、または、場合によってはターゲット プロパティからソース プロパティへデータを転送します。 ソース プロパティとターゲット プロパティの型が同じ場合、または、暗黙の型変換によって一方の型がもう一方の型に変換できる場合は、この転送はすみやかに進みます。 それ以外の場合は、型変換を行う必要があります。
文字列の書式設定に関する記事では、データ バインディングの StringFormat
プロパティを使用して任意の型を文字列に変換する方法について説明しました。 それ以外の型の変換では、IValueConverter インターフェイスを実装するクラス内に専用のコードを記述する必要があります IValueConverter を実装するクラスは、値コンバーターと呼ばれますが、バインディング コンバーターまたはバインディング値コンバーターと呼ばれることもよくあります。
バインディングの値コンバーター
ソース プロパティの型は int
だが、ターゲット プロパティは bool
の場合のデータ バインディングの定義を検討します。 このデータ バインディングでは、整数のソースが 0 に等しい場合に false
を、それ以外の場合は true
を生成する予定です。 これを行うには、IValueConverter インターフェイスを実装するクラスを使用します。
public class IntToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value != 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 1 : 0;
}
}
次に、このクラスのインスタンスを Binding
クラスの Converter
プロパティまたは Binding
マークアップ拡張の Converter
プロパティに設定します。 このクラスは、データ バインディングの一部になります。
OneWay
または TwoWay
バインディング内でソースからターゲットにデータを移行するときに、Convert
メソッドが呼び出されます。 value
パラメーターは、データ バインディング ソースからのオブジェクトまたは値になります。 メソッドは、データ バインディング ターゲットの型の値を返す必要があります。 ここに示したメソッドでは、value
パラメーターを int
にキャストして、その値を bool
戻り値の 0 と比較しています。
TwoWay
または OneWayToSource
バインディング内でターゲットから ースにデータを移行するときに、ConvertBack
メソッドが呼び出されます。 ConvertBack
は逆の変換を実行します。value
パラメーターがターゲットからの bool
であり、その値をソースの int
戻り値に変換することを想定しています。
Note
データ バインディングに StringFormat
設定も含まれている場合、結果が文字列として書式設定される前に、値コンバーターが呼び出されます。
次の例では、データ バインディングでこの値コンバーターを使用する方法を示します。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.EnableButtonsPage"
Title="Enable Buttons">
<ContentPage.Resources>
<local:IntToBoolConverter x:Key="intToBool" />
</ContentPage.Resources>
<StackLayout Padding="10, 0">
<Entry x:Name="entry1"
Text=""
Placeholder="enter search term"
VerticalOptions="Center" />
<Button Text="Search"
HorizontalOptions="Center"
VerticalOptions="Center"
IsEnabled="{Binding Source={x:Reference entry1},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
<Entry x:Name="entry2"
Text=""
Placeholder="enter destination"
VerticalOptions="Center" />
<Button Text="Submit"
HorizontalOptions="Center"
VerticalOptions="Center"
IsEnabled="{Binding Source={x:Reference entry2},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
</StackLayout>
</ContentPage>
この例では、IntToBoolConverter
をページのリソース ディクショナリ内でインスタンス化しています。 次に、StaticResource
マークアップ拡張を使用して参照し、2 つのデータ バインディングで Converter
プロパティを設定します。 ページ上の複数のデータ バインディング間でデータ コンバーターを共有することは、極めて一般的です アプリケーションの複数のページで値コンバーターが使用されている場合は、アプリケーション レベルのリソース ディクショナリ内でインスタンス化できます。
この例は、ユーザーが Entry ビューに入力したテキストに基づいて Button が操作を実行する場合の一般的なニーズを示しています。 Text
プロパティの既定値は null
であり、その場合はデータ バインディングが機能しないため、各 Entry の Text
プロパティは空の文字列として初期化されます。 Entry に何も入力されなかった場合は、Button を無効にする必要があります。 各 Button は、IsEnabled
プロパティ上にデータ バインディングを含みます。 データ バインディング ソースは、対応する Entry の Text
プロパティの Length
プロパティです。 その Length
プロパティが 0 ではない場合、値コンバーターは true
を返し、Button は有効になります。
Note
値コンバーターが OneWay
バインディング内のみで使用されることがわかっている場合、ConvertBack
メソッドは単純に null
を返すことができます。
上記の Convert
メソッドでは、暗黙的に value
引数の型は int
であり、戻り値の型は bool
であることを想定しています。 同様に、ConvertBack
メソッドでは、value
引数の型は bool
であり、戻り値は int
であることを想定しています。 これに該当しない場合、ランタイム例外が発生します。
より汎用化されるように、また、複数の異なるデータ型を許可するように、値コンバーターを記述できます。 Convert
および ConvertBack
メソッドでは、value
パラメーターと共に as
または is
演算子を使用できます。または、このパラメーター上で GetType
を呼び出して、値の型を特定してから、適切な処理を実行することが可能です。 各メソッドの戻り値で想定される型は、targetType
パラメーターによって指定されます。 値コンバーターは、さまざまなターゲット型のデータ バインディングと共に使用される場合があります。 この場合、値コンバーターは targetType
引数を使用して正しい型への変換を実行できます。
別のカルチャに対しては実行される変換が異なる場合には、この目的のために culture
パラメーターを使用します。
バインディング コンバーター プロパティ
値コンバーターのクラスには、プロパティとジェネリック パラメーターを含めることができます。 次の値コンバーターは、ソースからターゲットの T
型オブジェクトに bool
を変換します。
public class BoolToObjectConverter<T> : IValueConverter
{
public T TrueObject { get; set; }
public T FalseObject { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? TrueObject : FalseObject;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((T)value).Equals(TrueObject);
}
}
次の例では、このコンバーターを使用して Switch ビューの値を表示する方法を示します。 一般的にはリソース ディクショナリ内でリソースとして値コンバーターをインスタンス化しますが、この例では別の方法を示しています。 ここでは、各値コンバーターが Binding.Converter
プロパティ要素タグ間でインスタンス化されています。 x:TypeArguments
は汎用の引数を示し、TrueObject
および FalseObject
は両方とも、その型のオブジェクトに設定されます。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SwitchIndicatorsPage"
Title="Switch Indicators">
<ContentPage.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="18" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>
<Style TargetType="Switch">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</ContentPage.Resources>
<StackLayout Padding="10, 0">
<StackLayout Orientation="Horizontal"
VerticalOptions="Center">
<Label Text="Subscribe?" />
<Switch x:Name="switch1" />
<Label>
<Label.Text>
<Binding Source="{x:Reference switch1}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Of course!"
FalseObject="No way!" />
</Binding.Converter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
<StackLayout Orientation="Horizontal"
VerticalOptions="Center">
<Label Text="Allow popups?" />
<Switch x:Name="switch2" />
<Label>
<Label.Text>
<Binding Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Yes"
FalseObject="No" />
</Binding.Converter>
</Binding>
</Label.Text>
<Label.TextColor>
<Binding Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Color"
TrueObject="Green"
FalseObject="Red" />
</Binding.Converter>
</Binding>
</Label.TextColor>
</Label>
</StackLayout>
<StackLayout Orientation="Horizontal"
VerticalOptions="Center">
<Label Text="Learn more?" />
<Switch x:Name="switch3" />
<Label FontSize="18"
VerticalOptions="Center">
<Label.Style>
<Binding Source="{x:Reference switch3}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Style">
<local:BoolToObjectConverter.TrueObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Indubitably!" />
<Setter Property="FontAttributes" Value="Italic, Bold" />
<Setter Property="TextColor" Value="Green" />
</Style>
</local:BoolToObjectConverter.TrueObject>
<local:BoolToObjectConverter.FalseObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Maybe later" />
<Setter Property="FontAttributes" Value="None" />
<Setter Property="TextColor" Value="Red" />
</Style>
</local:BoolToObjectConverter.FalseObject>
</local:BoolToObjectConverter>
</Binding.Converter>
</Binding>
</Label.Style>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>
この例では、最後の 3 つの Switch と Label のペアで、汎用の引数が Style に設定され、Style オブジェクト全体が TrueObject
と FalseObject
の値に指定されています。 これらは、リソース ディクショナリ内の Label 設定の暗黙的な形式をオーバーライドしているので、その形式のプロパティが Label に明示的に割り当てられます。 Switch を切り替えると、対応する Label に変更が反映されます。
Note
トリガーを使用して、他のビューに基づいてユーザー インターフェイスに変更を実装することもできます。 詳細については、トリガーを参照してください。
バインディング コンバーター パラメーター
Binding
クラスは ConverterParameter
プロパティを定義し、Binding
マークアップ拡張も ConverterParameter
プロパティを定義します。 このプロパティが設定された場合、値は Convert
および ConvertBack
メソッドに parameter
引数として渡されます。 複数のデータ バインディング間で値コンバーターのインスタンスが共有されている場合でも、異なる変換を実行するために、ConverterParameter
は異なる可能性があります。
色選択のプログラムを利用して、ConverterParameter
プロパティの使用例を示します。 この例では、RgbColorViewModel
には、Color 値を構成するために使用される Red
、Green
、Blue
という名前の float
型の 3 つのプロパティがあることを示しています。
public class RgbColorViewModel : INotifyPropertyChanged
{
Color color;
string name;
public event PropertyChangedEventHandler PropertyChanged;
public float Red
{
get { return color.Red; }
set
{
if (color.Red != value)
{
Color = new Color(value, color.Green, color.Blue);
}
}
}
public float Green
{
get { return color.Green; }
set
{
if (color.Green != value)
{
Color = new Color(color.Red, value, color.Blue);
}
}
}
public float Blue
{
get { return color.Blue; }
set
{
if (color.Blue != value)
{
Color = new Color(color.Red, color.Green, value);
}
}
}
public Color Color
{
get { return color; }
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Red"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Green"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Blue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
Name = NamedColor.GetNearestColorName(color);
}
}
}
public string Name
{
get { return name; }
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
Red
、Green
、Blue
プロパティ値の範囲は 0 から 1 の間になります。 ただし、コンポーネントが 2 桁の 16 進数値として表示される方が望ましい場合があります。 これらを XAML 内で 16 進数値として表示するには、255 で乗算し、整数に変換してから、StringFormat
プロパティの "X2" の仕様を使って書式設定する必要があります。 255 で乗算し、整数に変換するには、値コンバーターを使用します。 値コンバーターをできる限り汎用化するために、乗算の係数は ConverterParameter
プロパティを使って指定できます。つまり、Convert
および ConvertBack
メソッドを parameter
引数として入力することになります。
public class FloatToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)Math.Round((float)value * GetParameter(parameter));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value / GetParameter(parameter);
}
double GetParameter(object parameter)
{
if (parameter is float)
return (float)parameter;
else if (parameter is int)
return (int)parameter;
else if (parameter is string)
return float.Parse((string)parameter);
return 1;
}
}
この例では、Convert
メソッドは parameter
値を乗算しながら float
から int
に変換します。 ConvertBack
メソッドは、整数 value
引数を parameter
で除算して float
の結果を返します。
parameter
引数の型は、データ バインディングが XAML で定義されているかコードで定義されているかに応じて異なる可能性があります。 コード内で Binding
の ConverterParameter
プロパティが設定されている場合、通常は、数値型の値に設定されます。
binding.ConverterParameter = 255;
ConverterParameter
プロパティは Object
型なので、C# コンパイラはリテラルの 255 を整数として解釈し、プロパティにその値を設定します。
ただし、XAML では通常、ConverterParameter
は次のように設定されます。
<Label Text="{Binding Red,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />
255 は数字のように見えますが、ConverterParameter
は Object
型なので、XAML パーサーでは 255 を文字列として処理します。 そのため、上記の値コンバーターには、parameter
が float
、int
、または string
型の場合に対処する GetParameter
メソッドが別途含まれています。
次の XAML 例では、FloatToIntConverter
のインスタンス化をそのリソース ディクショナリで行っています。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.RgbColorSelectorPage"
Title="RGB Color Selector">
<ContentPage.BindingContext>
<local:RgbColorViewModel Color="Gray" />
</ContentPage.BindingContext>
<ContentPage.Resources>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<local:FloatToIntConverter x:Key="floatToInt" />
</ContentPage.Resources>
<StackLayout Margin="20">
<BoxView Color="{Binding Color}"
HeightRequest="100"
WidthRequest="100"
HorizontalOptions="Center" />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Red}" />
<Label Text="{Binding Red,
Converter={StaticResource floatToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />
<Slider Value="{Binding Green}" />
<Label Text="{Binding Green,
Converter={StaticResource floatToInt},
ConverterParameter=255,
StringFormat='Green = {0:X2}'}" />
<Slider Value="{Binding Blue}" />
<Label>
<Label.Text>
<Binding Path="Blue"
StringFormat="Blue = {0:X2}"
Converter="{StaticResource floatToInt}">
<Binding.ConverterParameter>
<x:Single>255</x:Single>
</Binding.ConverterParameter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>
Red
および Green
プロパティの値は、Binding
マークアップ拡張を使って表示されます。 ただし、Blue
プロパティは Binding
クラスをインスタンス化して、明示的な float
値を ConverterParameter
プロパティに設定できる方法を示します。
.NET MAUI