Partager via


Convertisseurs de valeur de liaison

Browse sample. Parcourir l’exemple

Les liaisons de données de l’interface utilisateur d’application multiplateforme .NET (.NET MAUI) transfèrent généralement des données d’une propriété source vers une propriété cible, et, dans certains cas, de la propriété cible à la propriété source. Ce transfert est direct lorsque les propriétés source et cible sont du même type, ou quand un type peut être converti vers l’autre type via une conversion implicite. Lorsque ce n’est pas le cas, une conversion de type doit avoir lieu.

Dans l’article de mise en forme de chaîne, vous avez vu comment utiliser la StringFormat propriété d’une liaison de données pour convertir n’importe quel type en chaîne. Pour les autres types de conversions, vous devez écrire du code spécialisé dans une classe qui implémente l’interface IValueConverter. Les classes qui implémentent IValueConverter sont appelées convertisseurs de valeur, mais elles sont également souvent appelées convertisseurs de liaison ou convertisseurs de valeur de liaison.

Convertisseurs de valeur de liaison

Supposons que vous souhaitiez définir une liaison de données où la propriété source soit de type int mais la propriété cible de type bool. Vous souhaitez que cette liaison de données produise une valeur false lorsque la source entière est égale à 0, et true dans le cas contraire. Cette opération peut être obtenue avec une classe qui implémente l’interface 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;
    }
}

Vous définissez ensuite une instance de cette classe sur la Converter propriété de la Binding classe ou sur la Converter propriété de l’extension Binding de balisage. Cette classe devient partie intégrante de la liaison de données.

La méthode Convert est appelée lorsque les données sont transférées de la source vers la cible dans des liaisons OneWay ou TwoWay. Le paramètre value correspond à l’objet ou la valeur de la source de liaison de données. La méthode doit retourner une valeur du type de la cible de liaison de données. La méthode illustrée ici caste le paramètre value en int puis le compare à 0 pour une valeur renvoyée bool.

La méthode ConvertBack est appelée lorsque les données sont transférées de la cible vers la source dans des liaisons TwoWay ou OneWayToSource. ConvertBack effectue la conversion inverse : il suppose que le paramètre value est un bool issu de la cible et le convertit en une valeur renvoyée int pour la source.

Remarque

Si une liaison de données inclut également un StringFormat paramètre, le convertisseur de valeurs est appelé avant que le résultat soit mis en forme sous forme de chaîne.

L’exemple suivant montre comment utiliser ce convertisseur de valeurs dans une liaison de données :

<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>

Dans cet exemple, l’instanciation IntToBoolConverter est instanciée dans le dictionnaire de ressources de la page. Il est ensuite référencé avec une StaticResource extension de balisage pour définir la Converter propriété dans deux liaisons de données. Il est très courant de partager des convertisseurs de données entre plusieurs liaisons de données sur la page. Si un convertisseur de valeurs est utilisé dans plusieurs pages de votre application, vous pouvez l’instancier dans le dictionnaire de ressources au niveau de l’application.

Cet exemple illustre un besoin courant lorsqu’une Button opération est effectuée en fonction du texte que l’utilisateur tape dans une Entry vue. La Text propriété de chacune d’elles Entry est initialisée dans une chaîne vide, car la Text propriété est null par défaut, et la liaison de données ne fonctionnera pas dans ce cas. Si rien n’a été saisi dans Entry, l’élément Button doit être désactivé. Chaque élément Button contient une liaison de données sur sa propriété IsEnabled. La source de liaison de données est la propriété Length de la propriété Text de l’élément Entry correspondant. Si cette propriété Length n’est pas égale à 0, le convertisseur de valeurs retourne true et le Button est activé :

Enable buttons.

Remarque

Si vous savez qu’un convertisseur de valeurs servira uniquement dans des liaisons OneWay, la méthode ConvertBack peut retourner simplement null.

La Convert méthode indiquée ci-dessus suppose que l’argument value est de type int et que la valeur de retour doit être de type bool. De même, la méthode ConvertBack suppose que l’argument value est de type bool et que la valeur renvoyée est de type int. Si tel n’est pas le cas, une exception runtime se produit.

Vous pouvez écrire des convertisseurs de valeur plus généralisés qui acceptent plusieurs types de données différents. Les méthodes Convert et ConvertBack peuvent utiliser les opérateurs as et is avec le paramètre value, ou peuvent appeler GetType sur ce paramètre pour déterminer son type, puis prendre une mesure appropriée. Le type attendu de la valeur renvoyée de chaque méthode est fourni par le paramètre targetType. Parfois, les convertisseurs de valeurs sont utilisés avec des liaisons de données de différents types cibles. Dans ce cas, le convertisseur de valeurs peut utiliser l’argument targetType pour effectuer une conversion pour le type correct.

Si la conversion effectuée est différente pour différentes cultures, utilisez le paramètre culture à cet effet.

Propriétés du convertisseur de liaison

Les classes de convertisseur de valeurs peuvent avoir des propriétés et des paramètres génériques. Le convertisseur de valeurs suivant convertit une bool source en objet de type T pour la cible :

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

L’exemple suivant montre comment ce convertisseur peut être utilisé pour afficher la valeur d’une Switch vue. Bien qu’il soit courant d’instancier des convertisseurs de valeurs en tant que ressources dans un dictionnaire de ressources, cet exemple illustre une alternative. Ici, chaque convertisseur de valeur est instancié entre les balises d’élément Binding.Converter de propriété. x:TypeArguments indique l’argument générique, et TrueObject et FalseObject sont tous les deux définis sur des objets de ce type :

<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>

Dans cet exemple, dans le dernier des trois Switch et paires, l’argument générique est défini sur un Style, et les objets entiers Style sont fournis pour les valeurs et TrueObject FalseObject.Label Ceux-ci remplacent le style implicite pour Label, défini dans le dictionnaire de ressources, afin que les propriétés figurant dans ce style soient explicitement affectées à l’objet Label. Lors de l’activation/la désactivation de Switch, l’objet Label correspondant reflète la modification :

Switch indicators.

Remarque

Il est également possible d’utiliser des déclencheurs pour implémenter des modifications dans l’interface utilisateur en fonction d’autres vues. Pour en savoir plus, consultez Déclencheurs.

Paramètres de convertisseur de liaison

La classe Binding définit une propriété ConverterParameter et l’extension de balisage Binding définit également une propriété ConverterParameter. Si cette propriété est définie, la valeur est transmise aux méthodes Convert et ConvertBack en tant qu’argument parameter. Même si l’instance du convertisseur de valeur est partagée entre plusieurs liaisons de données, elle ConverterParameter peut être différente pour effectuer différentes conversions.

L’utilisation de la ConverterParameter propriété peut être illustrée avec un programme de sélection de couleurs. L’exemple suivant montre le RgbColorViewModel, qui a trois propriétés de type float nommé Red, Greenet Blue qu’il utilise pour construire une Color valeur :

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

Les Redvaleurs , Greenet les valeurs de propriété peuvent être comprises entre 0 et Blue 1. Toutefois, vous préférerez peut-être que les composants soient affichés en tant que valeurs hexadécimales à deux chiffres. Pour les afficher en tant que valeurs hexadécimales en XAML, ils doivent être multipliés par 255, convertis en entiers puis formatés avec une spécification de « X2 » dans la propriété StringFormat. La multiplication par 255 et la conversion en entier peuvent être effectuées par le convertisseur de valeurs. Pour généraliser le plus possible le convertisseur de valeur, le facteur de multiplication peut être spécifié avec la propriété ConverterParameter, ce qui signifie qu’il entre les méthodes Convert et ConvertBack en tant qu’argument 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;
    }
}

Dans cet exemple, la Convert méthode se convertit d’une float à l’autre int en multipliant par la parameter valeur. La ConvertBack méthode divise l’argument entier value par parameter et retourne un float résultat.

Le type de l’argument parameter est susceptible d’être différent selon que la liaison de données est définie en XAML ou en code. Si la propriété ConverterParameter de Binding est définie dans le code, l’argument est probablement défini sur une valeur numérique :

binding.ConverterParameter = 255;

La propriété ConverterParameter est de type Object, si bien que le compilateur C# interprète le littéral 255 comme un entier et définit la propriété sur cette valeur.

Toutefois, en XAML, il ConverterParameter est susceptible d’être défini comme suit :

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

Bien que 255 ressemble à un nombre, car ConverterParameter il est de type Object, l’analyseur XAML traite 255 comme une chaîne. Pour cette raison, le convertisseur de valeurs inclut une méthode distincte GetParameter qui gère les cas d’être parameter de type float, intou string.

L’exemple XAML suivant instancie FloatToIntConverter dans son dictionnaire de ressources :

<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>

Les valeurs des propriétés Red et Green sont affichées avec une extension de balisage Binding. Toutefois, la Blue propriété instancie la Binding classe pour montrer comment une valeur explicite float peut être définie sur ConverterParameter la propriété :

RGB color selector.