Convertisseurs de valeur de liaison
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é :
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 :
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
, Green
et 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 Red
valeurs , Green
et 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
, int
ou 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é :