バインディング値変換器

サンプルを参照します。 サンプルを参照する

.NET マルチプラットフォーム アプリ 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;
    }
}

次に、このクラスのインスタンスを、Converter クラスのBinding プロパティ、またはConverterマークアップ拡張のBinding プロパティに設定します。 このクラスは、データ バインディングの一部になります。

Convert メソッドは、OneWayバインディングまたはTwoWayバインディングでソースからターゲットにデータが移動されるときに呼び出されます。 value パラメーターは、データ バインディング ソースのオブジェクトまたは値です。 このメソッドは、データ バインディング ターゲットの型の値を返す必要があります。 ここで示すメソッドは、 value パラメーターを int にキャストし、 bool 戻り値を 0 と比較します。

ConvertBack メソッドは、データがターゲットからTwoWayまたはOneWayToSourceバインド内のソースに移動するときに呼び出されます。 ConvertBack は逆の変換を実行します。 value パラメーターがターゲットからの bool であると想定し、ソースの int 戻り値に変換します。

データ バインディングに 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 x:DataType="Entry"
                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 x:DataType="Entry"
                Text="Submit"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                IsEnabled="{Binding Source={x:Reference entry2},
                                    Path=Text.Length,
                                    Converter={StaticResource intToBool}}" />
    </StackLayout>
</ContentPage>

この例では、 IntToBoolConverter はページのリソース ディクショナリでインスタンス化されます。 その後、2 つのデータ バインディングでStaticResource プロパティを設定するために、Converterマークアップ拡張機能で参照されます。 ページ上の複数のデータ バインディング間でデータ コンバーターを共有することは非常に一般的です。 値コンバーターがアプリケーションの複数のページで使用されている場合は、アプリケーション レベルのリソース ディクショナリでインスタンス化できます。

この例では、 Button がユーザーが Entry ビューに入力したテキストに基づいて操作を実行する場合の一般的なニーズを示します。 各TextEntry プロパティは空の文字列に初期化されます。これは、Text プロパティが既定でnullされ、その場合はデータ バインディングが機能しないためです。 Entryに何も入力されていない場合は、Buttonを無効にする必要があります。 各 Button には、 IsEnabled プロパティのデータ バインディングが含まれています。 データ バインディング ソースは、対応するLengthText プロパティのEntry プロパティです。 その Length プロパティが 0 でない場合、値コンバーターは true を返し、 Button が有効になります。

ボタンを有効にします。

値コンバーターが OneWay バインドでのみ使用されることがわかっている場合、 ConvertBack メソッドは単に nullを返すことができます。

上記の Convert メソッドは、 value 引数が int 型であり、戻り値が bool型である必要があることを前提としています。 同様に、 ConvertBack メソッドは、 value 引数が bool 型であり、戻り値が intされていることを前提としています。 そうでない場合は、ランタイム例外が発生します。

値コンバーターを記述して、より一般化し、さまざまな種類のデータを受け入れることもできます。 ConvertメソッドとConvertBack メソッドでは、as パラメーターでis演算子またはvalue演算子を使用することも、そのパラメーターに対してGetTypeを呼び出して型を決定し、適切な操作を実行することもできます。 各メソッドの戻り値の予期される型は、 targetType パラメーターによって指定されます。 値コンバーターは、さまざまなターゲット型のデータ バインディングと共に使用される場合があります。 この場合、値コンバーターは targetType 引数を使用して、正しい型の変換を実行できます。

実行される変換がカルチャによって異なる場合は、この目的で culture パラメーターを使用します。

バインディング コンバーターのプロパティ

値コンバーター クラスは、プロパティとジェネリック パラメーターを持つことができます。 次の値コンバーターは、ソースからターゲットのbool型のオブジェクトにTを変換します。

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 property-element タグ間でインスタンス化されます。 x:TypeArgumentsはジェネリック引数を示し、TrueObjectFalseObjectはどちらもその型のオブジェクトに設定されます。

<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 x:DataType="Switch"
                             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 x:DataType="Switch"
                             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 x:DataType="Switch"
                             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 x:DataType="Switch"
                             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 つのSwitchLabelのペアの最後で、ジェネリック引数がStyleに設定され、StyleTrueObjectの値に対してFalseObjectオブジェクト全体が指定されます。 これにより、リソース ディクショナリで設定 Label の暗黙的なスタイルがオーバーライドされるため、そのスタイルのプロパティが Labelに明示的に割り当てられます。 Switchを切り替えることで、対応するLabelに変更が反映されます。

インジケーターを切り替えます。

トリガーを使用して、他のビューに基づいてユーザー インターフェイスに変更を実装することもできます。 詳細については、「 トリガー」を参照してください。

バインディング コンバーターのパラメーター

Binding クラスはConverterParameterプロパティを定義し、Bindingマークアップ拡張ではConverterParameterプロパティも定義します。 このプロパティが設定されている場合、値はConvert引数としてConvertBackメソッドとparameterメソッドに渡されます。 値コンバーターのインスタンスが複数のデータ バインディング間で共有されている場合でも、 ConverterParameter は異なる変換を実行するために異なる場合があります。

ConverterParameterプロパティの使用は、色選択プログラムで示すことができます。 次の例は、RgbColorViewModelfloat 型の 3 つのプロパティ、RedGreen、およびBlueを使用してColor値を構築することを示しています。

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"));
            }
        }
    }
}

RedGreen、および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 メソッドは、float値を乗算しながら、intからparameterに変換します。 ConvertBack メソッドは、引数value整数をparameterで除算し、float結果を返します。

parameter引数の型は、データ バインディングが XAML で定義されているかコードで定義されているかによって異なる可能性があります。 ConverterParameterBinding プロパティがコードで設定されている場合は、数値に設定される可能性があります。

binding.ConverterParameter = 255;

ConverterParameter プロパティはObject型であるため、C# コンパイラはリテラル 255 を整数として解釈し、プロパティをその値に設定します。

ただし、XAML では、 ConverterParameter は次のように設定される可能性があります。

<Label Text="{Binding Red,
                      Converter={StaticResource doubleToInt},
                      ConverterParameter=255,
                      StringFormat='Red = {0:X2}'}" />

255 は数値のように見えますが、 ConverterParameterObject型であるため、XAML パーサーは 255 を文字列として扱います。 このため、値コンバーターには、GetParameterparameter、またはfloatintのケースを処理する個別のstring メソッドが含まれています。

次の 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"
             x:DataType="local:RgbColorViewModel">
    <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 プロパティは、float クラスのインスタンスを作成して、明示的なBinding 値をConverterParameter プロパティに設定する方法を示します。

RGB カラー セレクター。