Xamarin.Forms バインディングの値コンバーターXamarin.Forms Binding Value Converters

サンプルのダウンロードサンプルのダウンロードDownload Sample Download the sample

データ バインディングでは通常、ソース プロパティからターゲット プロパティへ、または、場合によってはターゲット プロパティからソース プロパティへ、データを転送します。Data bindings usually transfer data from a source property to a target property, and in some cases from the target property to the source property. ソース プロパティとターゲット プロパティの型が同じ場合、または、暗黙の型変換によって一方の型がもう一方の型に変換できる場合は、この転送はすみやかに進みます。This transfer is straightforward when the source and target properties are of the same type, or when one type can be converted to the other type through an implicit conversion. それ以外の場合は、型変換を行う必要があります。When that is not the case, a type conversion must take place.

文字列の書式設定に関する記事では、データ バインディングの StringFormat プロパティを使用して任意の型を文字列に変換する方法を確認しました。In the String Formatting article, you saw how you can use the StringFormat property of a data binding to convert any type into a string. それ以外の型の変換では、IValueConverter インターフェイスを実装するクラス内に専用のコードを記述する必要があります For other types of conversions, you need to write some specialized code in a class that implements the IValueConverter interface. (ユニバーサル Windows プラットフォームには、Windows.UI.Xaml.Data 名前空間内に IValueConverter という名前の類似のクラスが含まれますが、この IValueConverterXamarin.Forms 名前空間内にあります)。IValueConverter を実装するクラスは、値コンバーターと呼ばれますが、バインディング コンバーターまたはバインディング値コンバーターと呼ばれることもよくあります。(The Universal Windows Platform contains a similar class named IValueConverter in the Windows.UI.Xaml.Data namespace, but this IValueConverter is in the Xamarin.Forms namespace.) Classes that implement IValueConverter are called value converters, but they are also often referred to as binding converters or binding value converters.

IValueConverter インターフェイスThe IValueConverter Interface

ソース プロパティの型は int だが、ターゲット プロパティは bool の場合のデータ バインディングの定義を検討します。Suppose you want to define a data binding where the source property is of type int but the target property is a bool. このデータ バインディングでは、整数のソースが 0 に等しい場合に false を、それ以外の場合は true を生成する予定です。You want this data binding to produce a false value when the integer source is equal to 0, and true otherwise.

これは、IValueConverter インターフェイスを実装するクラスを使って実現できます。You can do this with a class that implements the IValueConverter interface:

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 プロパティに設定します。You set an instance of this class to the Converter property of the Binding class or to the Converter property of the Binding markup extension. このクラスは、データ バインディングの一部になります。This class becomes part of the data binding.

OneWay または TwoWay バインディング内でソースからターゲットにデータを移行するときに、Convert メソッドが呼び出されます。The Convert method is called when data moves from the source to the target in OneWay or TwoWay bindings. value パラメーターは、データ バインディング ソースからのオブジェクトまたは値になります。The value parameter is the object or value from the data-binding source. メソッドは、データ バインディング ターゲットの型の値を返す必要があります。The method must return a value of the type of the data-binding target. ここに示したメソッドでは、value パラメーターを int にキャストして、その値を bool 戻り値の 0 と比較しています。The method shown here casts the value parameter to an int and then compares it with 0 for a bool return value.

TwoWay または OneWayToSource バインディング内でターゲットから ースにデータを移行するときに、ConvertBack メソッドが呼び出されます。The ConvertBack method is called when data moves from the target to the source in TwoWay or OneWayToSource bindings. ConvertBack は逆の変換を実行します。value パラメーターがターゲットからの bool であり、その値をソースの int 戻り値に変換することを想定しています。ConvertBack performs the opposite conversion: It assumes the value parameter is a bool from the target, and converts it to an int return value for the source.

データ バインディングにも StringFormat 設定が含まれている場合、結果が文字列として書式設定される前に、値コンバーターが呼び出されます。If the data binding also includes a StringFormat setting, the value converter is invoked before the result is formatted as a string.

Data Binding Demos (データ バインディング デモ) サンプルのEnable Buttons (ボタンの有効化) のページでは、データ バインディング内でこの値コンバーターを使用する方法のサンプルを示しています。The Enable Buttons page in the Data Binding Demos sample demonstrates how to use this value converter in a data binding. IntToBoolConverter は、ページのリソース ディクショナリ内でインスタンス化されます。The IntToBoolConverter is instantiated in the page's resource dictionary. その後、2 つのデータ バインディングに Converter プロパティを設定するために、StaticResource マークアップ拡張を使って参照されます。It is then referenced with a StaticResource markup extension to set the Converter property in two data bindings. ページ上の複数のデータ バインディング間でデータ コンバーターを共有することは、極めて一般的ですIt is very common to share data converters among multiple data bindings on the page:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.EnableButtonsPage"
             Title="Enable Buttons">
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:IntToBoolConverter x:Key="intToBool" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <Entry x:Name="entry1"
               Text=""
               Placeholder="enter search term"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Search"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                IsEnabled="{Binding Source={x:Reference entry1},
                                    Path=Text.Length,
                                    Converter={StaticResource intToBool}}" />

        <Entry x:Name="entry2"
               Text=""
               Placeholder="enter destination"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Submit"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                IsEnabled="{Binding Source={x:Reference entry2},
                                    Path=Text.Length,
                                    Converter={StaticResource intToBool}}" />
    </StackLayout>
</ContentPage>

アプリケーションの複数のページで値コンバーターが使用されている場合は、App.xaml ファイルのリソース ディクショナリ内でインスタンス化できます。If a value converter is used in multiple pages of your application, you can instantiate it in the resource dictionary in the App.xaml file.

Enable Buttons のページでは、ユーザーが Entry ビューに入力するテキストに基づいて Button による操作が実行される場合の、一般的なニーズを示しています。The Enable Buttons page demonstrates a common need when a Button performs an operation based on text that the user types into an Entry view. Entry に何も入力されなかった場合は、Button を無効にする必要があります。If nothing has been typed into the Entry, the Button should be disabled. Button は、IsEnabled プロパティ上にデータ バインディングを含みます。Each Button contains a data binding on its IsEnabled property. データ バインディング ソースは、対応する EntryText プロパティの Length プロパティです。The data-binding source is the Length property of the Text property of the corresponding Entry. その Length プロパティが 0 ではない場合、値コンバーターは true を返し、Button は有効になります。If that Length property is not 0, the value converter returns true and the Button is enabled:

Enable Buttons (ボタンの有効化)Enable Buttons

EntryText プロパティは、空の文字列に初期化されることに注目してください。Notice that the Text property in each Entry is initialized to an empty string. Text プロパティは既定で null であり、その場合、データ バインディングは機能しません。The Text property is null by default, and the data binding will not work in that case.

値コンバーターが、明示的に特定のアプリケーションに向けて記述されている場合もありますが、それ以外は汎用化されています。Some value converters are written specifically for particular applications, while others are generalized. 値コンバーターが OneWay バインディング内のみで使用されることがわかっている場合、ConvertBack メソッドは単純に null を返すことができます。If you know that a value converter will only be used in OneWay bindings, then the ConvertBack method can simply return null.

上記の Convert メソッドでは、暗黙的に value 引数の型は int であり、戻り値の型は必ず bool であることを想定しています。The Convert method shown above implicitly assumes that the value argument is of type int and the return value must be of type bool. 同様に、ConvertBack メソッドでは、value 引数の型は bool であり、戻り値は int であることを想定しています。Similarly, the ConvertBack method assumes that the value argument is of type bool and the return value is int. これに該当しない場合、ランタイム例外が発生します。If that is not the case, a runtime exception will occur.

より汎用化されるように、また、複数の異なるデータ型を許可するように、値コンバーターを記述できます。You can write value converters to be more generalized and to accept several different types of data. Convert および ConvertBack メソッドでは、value パラメーターと共に as または is 演算子を使用できます。または、このパラメーター上で GetType を呼び出して、値の型を特定してから、適切な処理を実行することが可能です。The Convert and ConvertBack methods can use the as or is operators with the value parameter, or can call GetType on that parameter to determine its type, and then do something appropriate. 各メソッドの戻り値で想定される型は、targetType パラメーターによって指定されます。The expected type of each method's return value is given by the targetType parameter. 場合によっては、値コンバーターはさまざまなターゲット型のデータ バインディングに使用されます。値コンバーターは targetType 引数を使用して、正しい型への変換を実行できます。Sometimes, value converters are used with data bindings of different target types; the value converter can use the targetType argument to perform a conversion for the correct type.

別のカルチャに対しては実行される変換が異なる場合には、この目的のために culture パラメーターを使用します。If the conversion being performed is different for different cultures, use the culture parameter for this purpose. Convert および ConvertBack への parameter 引数については、この記事で後述します。The parameter argument to Convert and ConvertBack is discussed later in this article.

バインディング コンバーター プロパティBinding Converter Properties

値コンバーターのクラスには、プロパティとジェネリック パラメーターを含めることができます。Value converter classes can have properties and generic parameters. この特定の値コンバーターは、ソースからターゲットの T 型オブジェクトに bool を変換します。This particular value converter converts a bool from the source to an object of type T for the target:

public class BoolToObjectConverter<T> : IValueConverter
{
    public T TrueObject { set; get; }

    public T FalseObject { set; get; }

    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 Indicators (インジケーターの切り替え) のページは、Switch ビューの値を表示するために使用できる方法を示しています。The Switch Indicators page demonstrates how it can be used to display the value of a Switch view. リソース ディクショナリ内でリソースとして値コンバーターをインスタンス化することが一般的ですが、このページでは別の方法を示しています。各値コンバーターが Binding.Converter プロパティ要素タグ間でインスタンス化されています。Although it's common to instantiate value converters as resources in a resource dictionary, this page demonstrates an alternative: Each value converter is instantiated between Binding.Converter property-element tags. x:TypeArguments は汎用の引数を示し、TrueObject および FalseObject は両方とも、その型のオブジェクトに設定されます。The x:TypeArguments indicates the generic argument, and TrueObject and FalseObject are both set to objects of that type:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.SwitchIndicatorsPage"
             Title="Switch Indicators">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="18" />
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>

            <Style TargetType="Switch">
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <StackLayout Orientation="Horizontal"
                     VerticalOptions="CenterAndExpand">
            <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="CenterAndExpand">
            <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="CenterAndExpand">
            <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 つの SwitchLabel のペアでは、汎用の引数が Style に設定され、Style オブジェクト全体が TrueObject および FalseObject の値に指定されています。In the last of the three Switch and Label pairs, the generic argument is set to Style, and entire Style objects are provided for the values of TrueObject and FalseObject. これらは、リソース ディクショナリ内の Label 設定の暗黙的な形式をオーバーライドしているので、その形式のプロパティが Label に明示的に割り当てられます。These override the implicit style for Label set in the resource dictionary, so the properties in that style are explicitly assigned to the Label. Switch を切り替えると、対応する Label に変更が反映されます。Toggling the Switch causes the corresponding Label to reflect the change:

Switch Indicators (インジケーターの切り替え)Switch Indicators

また、Triggers を使用して、他のビューに基づくユーザー インターフェイス内に類似の変更を実装することも可能です。It's also possible to use Triggers to implement similar changes in the user-interface based on other views.

バインディング コンバーター パラメーターBinding Converter Parameters

Binding クラスは ConverterParameter プロパティを定義し、Binding マークアップ拡張も ConverterParameter プロパティを定義します。The Binding class defines a ConverterParameter property, and the Binding markup extension also defines a ConverterParameter property. このプロパティが設定された場合、値は Convert および ConvertBack メソッドに parameter 引数として渡されます。If this property is set, then the value is passed to the Convert and ConvertBack methods as the parameter argument. 複数のデータ バインディング間で値コンバーターのインスタンスが共有されたとしても、少し違った変換を実行するために、ConverterParameter は異なる可能性があります。Even if the instance of the value converter is shared among several data bindings, the ConverterParameter can be different to perform somewhat different conversions.

色選択のプログラムを利用して、ConverterParameter の使用例を示します。The use of ConverterParameter is demonstrated with a color-selection program. ここで、RgbColorViewModel には、Color 値を構成するために使用される RedGreenBlue という名前の double 型の 3 つのプロパティがあります。In this case, the RgbColorViewModel has three properties of type double named Red, Green, and Blue that it uses to construct a Color value:

public class RgbColorViewModel : INotifyPropertyChanged
{
    Color color;
    string name;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Red
    {
        set
        {
            if (color.R != value)
            {
                Color = new Color(value, color.G, color.B);
            }
        }
        get
        {
            return color.R;
        }
    }

    public double Green
    {
        set
        {
            if (color.G != value)
            {
                Color = new Color(color.R, value, color.B);
            }
        }
        get
        {
            return color.G;
        }
    }

    public double Blue
    {
        set
        {
            if (color.B != value)
            {
                Color = new Color(color.R, color.G, value);
            }
        }
        get
        {
            return color.B;
        }
    }

    public Color 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);
            }
        }
        get
        {
            return color;
        }
    }

    public string Name
    {
        private set
        {
            if (name != value)
            {
                name = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
            }
        }
        get
        {
            return name;
        }
    }
}

RedGreen、および Blue プロパティの範囲は 0 から 1 の間になります。The Red, Green, and Blue properties range between 0 and 1. ただし、コンポーネントが 2 桁の 16 進数値として表示される方が望ましい場合があります。However, you might prefer that the components be displayed as two-digit hexadecimal values.

これらを XAML 内で 16 進数値として表示するには、255 で乗算し、整数に変換してから、StringFormat プロパティの "X2" の仕様を使って書式設定する必要があります。To display these as hexadecimal values in XAML, they must be multiplied by 255, converted to an integer, and then formatted with a specification of "X2" in the StringFormat property. 最初の 2 つのタスク (255 で乗算し、整数に変換する) は、値コンバーターによって処理できます。The first two tasks (multiplying by 255 and converting to an integer) can be handled by the value converter. 値コンバーターをできる限り汎用化するために、乗算の係数は ConverterParameter プロパティを使って指定できます。つまり、Convert および ConvertBack メソッドを parameter 引数として入力することになります。To make the value converter as generalized as possible, the multiplication factor can be specified with the ConverterParameter property, which means that it enters the Convert and ConvertBack methods as the parameter argument:

public class DoubleToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (int)Math.Round((double)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 double)
            return (double)parameter;

        else if (parameter is int)
            return (int)parameter;

        else if (parameter is string)
            return double.Parse((string)parameter);

        return 1;
    }
}

Convertparameter 値で乗算している間に double から int への変換を行います。ConvertBack は整数の value 引数を parameter で除算し、double の結果を返します The Convert converts from a double to int while multiplying by the parameter value; the ConvertBack divides the integer value argument by parameter and returns a double result. (以下に示すプログラムでは、値コンバーターが文字列の書式設定との関連付けのみに使用されているので、ConvertBack は使用されていません)。(In the program shown below, the value converter is used only in connection with string formatting, so ConvertBack is not used.)

parameter 引数の型は、データ バインディングがコード内または XAML 内のどちらに定義されているかに応じて異なる可能性があります。The type of the parameter argument is likely to be different depending on whether the data binding is defined in code or XAML. コード内で BindingConverterParameter プロパティが設定されている場合、通常は、数値型の値に設定されます。If the ConverterParameter property of Binding is set in code, it's likely to be set to a numeric value:

binding.ConverterParameter = 255;

ConverterParameter プロパティは Object 型なので、C# コンパイラはリテラルの 255 を整数として解釈し、プロパティにその値を設定します。The ConverterParameter property is of type Object, so the C# compiler interprets the literal 255 as an integer, and sets the property to that value.

しかし、XAML では通常、ConverterParameter は次のように設定されます。In XAML, however, the ConverterParameter is likely to be set like this:

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

255 は数字のように見えますが、ConverterParameterObject 型なので、XAML パーサーでは 255 を文字列として処理します。The 255 looks like a number, but because ConverterParameter is of type Object, the XAML parser treats the 255 as a string.

そのため、上記の値コンバーターには、parameterdoubleint、または string 型の場合を処理する別個の GetParameter メソッドが含まれています。For that reason, the value converter shown above includes a separate GetParameter method that handles cases for parameter being of type double, int, or string.

RGB Color Selector (RGB カラー セレクター) のページでは、2 つの暗黙的な形式の定義に従って、リソース ディクショナリ内で DoubleToIntConverter をインスタンス化します。The RGB Color Selector page instantiates DoubleToIntConverter in its resource dictionary following the definition of two implicit styles:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.RgbColorSelectorPage"
             Title="RGB Color Selector">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Slider">
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>

            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>

            <local:DoubleToIntConverter x:Key="doubleToInt" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <StackLayout.BindingContext>
            <local:RgbColorViewModel Color="Gray" />
        </StackLayout.BindingContext>

        <BoxView Color="{Binding Color}"
                 VerticalOptions="FillAndExpand" />

        <StackLayout Margin="10, 0">
            <Label Text="{Binding Name}" />

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

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

            <Slider Value="{Binding Blue}" />
            <Label>
                <Label.Text>
                    <Binding Path="Blue"
                             StringFormat="Blue = {0:X2}"
                             Converter="{StaticResource doubleToInt}">
                        <Binding.ConverterParameter>
                            <x:Double>255</x:Double>
                        </Binding.ConverterParameter>
                    </Binding>
                </Label.Text>
            </Label>
        </StackLayout>
    </StackLayout>
</ContentPage>    

Red および Green プロパティの値は、Binding マークアップ拡張を使って表示されます。The values of the Red and Green properties are displayed with a Binding markup extension. しかし、明示的な double 値を ConverterParameter プロパティに設定できる方法を示すために、Blue プロパティは Binding クラスをインスタンス化します。The Blue property, however, instantiates the Binding class to demonstrate how an explicit double value can be set to ConverterParameter property.

結果は次のようになります。Here's the result:

RGB Color Selector (RGB カラー セレクター)RGB Color Selector