Bindungswertkonverter
Durchsuchen Sie den Beispielcode
.NET Multi-platform App UI (.NET MAUI)-Datenbindungen übertragen normalerweise Daten von einer Quelleigenschaft zu einer Zieleigenschaft und in einigen Fällen von der Zieleigenschaft zur Quelleigenschaft. Diese Umwandlung ist einfach, wenn die Quell- und Zieleigenschaften vom gleichen Typ sind oder wenn ein Typ über eine implizite Konvertierung in den anderen Typ konvertiert werden kann. Wenn dies nicht der Fall ist, muss eine Typkonvertierung durchgeführt werden.
Im Artikel Zeichenfolgenformatierung haben Sie gesehen, wie Sie die StringFormat
Eigenschaft einer Datenbindung verwenden können, um einen beliebigen Typ in eine Zeichenfolge zu konvertieren. Für andere Konvertierungstypen müssen Sie speziellen Code in einer Klasse schreiben, die die Schnittstelle IValueConverter implementiert. Klassen, die IValueConverter implementieren, werden Wertkonverter genannt. Sie werden allerdings auch oft als Bindungskonverter oder Bindungswertkonverter bezeichnet.
Bindungswertkonverter
Angenommen, Sie möchten eine Datenbindung definieren, bei der die Quelleigenschaft vom Typ int
, die Zieleigenschaft jedoch vom Typ bool
ist. Sie möchten, dass diese Datenbindung einen false
-Wert erzeugt, wenn die Integerquelle gleich 0 ist und andernfalls true
. Dies kann mit einer Klasse erreicht werden, welche die IValueConverter Schnittstelle implementiert:
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;
}
}
Sie setzen dann eine Instanz dieser Klasse auf die Converter
Eigenschaft der Binding
Klasse oder auf die Converter
Eigenschaft der Binding
Markup-Erweiterung. Diese Klasse wird Teil der Datenbindung.
Die Convert
-Methode wird aufgerufen, wenn Daten von der Quelle zum Ziel in OneWay
- oder TwoWay
-Bindungen verschoben werden. Der Parameter value
ist das Objekt oder der Wert der Quelle der Datenbindung. Die Methode muss einen Wert des Datenbindungszieltyps zurückgeben. Die hier dargestellte Methode wandelt den value
-Parameter in eine int
-Eigenschaft um und vergleicht diese dann mit „0“ für einen bool
-Rückgabewert.
Die ConvertBack
-Methode wird aufgerufen, wenn Daten vom Ziel zur Quelle in TwoWay
- oder OneWayToSource
-Bindungen verschoben werden. ConvertBack
führt die umgekehrte Konvertierung aus: Diese Methode geht davon aus, dass der value
-Parameter ein boolescher Wert (bool
) aus dem Ziel ist und konvertiert diesen in einen int
-Rückgabewert für die Quelle.
Hinweis
Wenn eine Datenbindung auch eine StringFormat
-Einstellung enthält, wird der Wertkonverter aufgerufen, bevor das Ergebnis als Zeichenkette formatiert wird.
Im folgenden Beispiel wird die Verwendung dieses Wertkonverters in einer Datenbindung veranschaulicht:
<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>
In diesem Beispiel wird IntToBoolConverter
im Ressourcenwörterbuch der Seite instanziiert. Es wird dann mit einer StaticResource
Markuperweiterung referenziert, um die Converter
-Eigenschaft in zwei Datenbindungen festzulegen. Es ist sehr üblich, Datenkonverter für mehrere Datenbindungen auf der Seite gemeinsam zu nutzen. Wenn ein Wertkonverter in mehreren Seiten Ihrer Anwendung verwendet wird, können Sie ihn im Ressourcenwörterbuch auf Anwendungsebene instanziieren.
Dieses Beispiel veranschaulicht eine häufige Notwendigkeit, wenn ein Button eine Operation auf der Grundlage von Text durchführt, den der/die Benutzer*innen in eine Entry-Ansicht eingibt. Die Text
Eigenschaft jeder Entry wird mit einem leeren Zeichenfolge initialisiert, da die Text
Eigenschaft standardmäßig null
ist und die Datenbindung in diesem Fall nicht funktioniert. Wenn nichts in die Entry-Ansicht eingegeben wurde, sollte die Schaltfläche (Button) deaktiviert werden. Jede Button-Klasse enthält eine Datenbindung für ihre IsEnabled
-Eigenschaft. Die Quelle der Datenbindung ist die Length
-Eigenschaft der Text
-Eigenschaft der entsprechenden Entry-Ansicht. Wenn diese Length
-Eigenschaft nicht 0 (null) ist, gibt der Wertkonverter true
zurück, und die Schaltfläche (Button) wird aktiviert:
Hinweis
Wenn Sie wissen, dass ein Wertkonverter nur in OneWay
-Bindungen verwendet wird, kann die ConvertBack
-Methode einfach null
zurückgeben.
Die oben gezeigte Convert
-Methode setzt voraus, dass das value
-Argument vom Typ int
ist und der Rückgabewert vom Typ bool
sein muss. Gleichzeitig geht die ConvertBack
-Methode davon aus, dass das value
-Argument vom Typ bool
und der Rückgabewert int
ist. Sollte dies nicht der Fall sein, wird eine Laufzeitausnahme ausgelöst.
Sie können Wertkonverter so schreiben, dass sie verallgemeinert werden und mehrere unterschiedliche Datentypen akzeptieren. Die Methoden Convert
und ConvertBack
können die Operatoren as
oder is
mit dem value
-Parameter verwenden oder GetType
für diesen Parameter aufrufen, um dessen Typ zu bestimmen und dann einen entsprechenden Vorgang auszuführen. Der erwartete Typ des Rückgabewerts jeder Methode wird vom targetType
-Parameter bestimmt. Manchmal werden Wertkonverter mit Datenbindungen unterschiedlicher Zieltypen verwendet. In diesem Fall kann der Wertkonverter das targetType
Argument verwenden, um eine Kovertierung für den richtigen Typ auszuführen.
Sollte sich die durchgeführte Konvertierung für unterschiedliche Kulturen unterscheiden, verwenden Sie zu diesem Zweck den culture
-Parameter.
Bindungskonverter-Eigenschaften
Wertkonverterklassen können über Eigenschaften und generische Parameter verfügen. Der folgende Wertkonverter wandelt ein bool
aus der Quelle in ein Objekt vom Typ T
für das Ziel um:
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);
}
}
Das folgende Beispiel zeigt, wie dieser Konverter verwendet werden kann, um den Wert einer Switch Ansicht anzuzeigen. Obwohl es üblich ist, Wertkonverter als Ressourcen in einem Ressourcenwörterbuch zu instanziieren, zeigt dieses Beispiel eine Alternative auf. Hier wird jeder Wertumwandler zwischen Binding.Converter
Eigenschaftselement-Tags instanziiert. Die Anweisung x:TypeArguments
gibt das generische Argument an, und TrueObject
und FalseObject
werden jeweils auf Objekte dieses Typs festgelegt:
<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>
In diesem Beispiel wird im letzten der drei Switch und Label Paare das generische Argument auf ein Style gesetzt, und für die Werte TrueObject
und FalseObject
werden ganze Style Objekte bereitgestellt. Diese überschreiben das impliziten Format für die im Ressourcenverzeichnis festgelegte Label-Klasse. Deshalb werden die Eigenschaften in diesem Format explizit zur Label-Klasse zugewiesen. Das Umschalten von Switch bewirkt, dass die entsprechende Label-Klasse die Änderung widerspiegelt:
Hinweis
Es ist auch möglich, Auslöser zu verwenden, um Änderungen in der Benutzeroberfläche basierend auf anderen Ansichten zu implementieren. Weitere Informationen finden Sie unter Trigger.
Parameter von Bindungskonvertern
Die Klasse Binding
definiert eine ConverterParameter
-Eigenschaft, und die Markuperweiterung Binding
definiert ebenfalls eine ConverterParameter
-Eigenschaft. Wenn diese Eigenschaft festgelegt ist, dann wird der Wert an die Methoden Convert
und ConvertBack
als parameter
-Argument übergeben. Auch wenn die Instanz des Wertkonverters von mehreren Datenbindungen gemeinsam genutzt wird, kann ConverterParameter
abweichen, um unterschiedliche Konvertierungen durchzuführen.
Die Verwendung der Eigenschaft ConverterParameter
kann mit einem Farbauswahlprogramm demonstriert werden. Das folgende Beispiel zeigt die RgbColorViewModel
, die drei Eigenschaften des Typs float
mit den Namen Red
, Green
und Blue
hat, die sie verwendet, um einen Color Wert zu konstruieren:
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"));
}
}
}
}
Die Werte der Eigenschaften Red
, Green
und Blue
können zwischen 0 und 1 liegen. Möglicherweise bevorzugen Sie, dass die Komponenten als zweistellige Hexadezimalwerte angezeigt werden. Damit sie diese als Hexadezimalwerte in XAML anzeigen können, müssen sie mit 255 multipliziert und in einen Integer konvertiert werden. Anschließend müssen Sie mit der Spezifikation „X2“ in die StringFormat
-Eigenschaft formatiert werden. Die Multiplikation mit 255 und die Umwandlung in eine ganze Zahl kann durch den Wertkonverter erfolgen. Sie können den Wertkonverter so allgemein wie möglich gestalten, indem Sie den Multiplikationsfaktor mit der Eigenschaft ConverterParameter
angeben. Das heißt, dass dieser die Convert
- und ConvertBack
-Methode als parameter
-Argument angibt:
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;
}
}
In diesem Beispiel wird die Methode Convert
von float
in int
konvertiert und multipliziert dabei mit dem parameter
Wert. Die Methode ConvertBack
teilt das ganzzahlige Argument value
durch parameter
und gibt ein float
Ergebnis zurück.
Der Typ des parameter
Arguments ist wahrscheinlich unterschiedlich, je nachdem, ob die Datenbindung in XAML oder Code definiert ist. Wenn die ConverterParameter
-Eigenschaft von Binding
in Code festgelegt ist, dann ist es wahrscheinlich, dass sie auf einen numerischen Wert festgelegt wird:
binding.ConverterParameter = 255;
Die ConverterParameter
-Eigenschaft ist vom Typ Object
, also interpretiert der C#-Compiler das Literal 255 als Integer und legt die Eigenschaft auf diesen Wert fest.
In XAML wird ConverterParameter
jedoch wahrscheinlich wie folgt gesetzt werden:
<Label Text="{Binding Red,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />
Während 255 wie eine Zahl aussieht, weil ConverterParameter
vom Typ Object
ist, behandelt der XAML-Parser 255 als Zeichenfolge. Aus diesem Grund enthält der Wertkonverter eine separate GetParameter
Methode, die Fälle behandelt, in denen parameter
vom Typ float
, int
oder string
ist.
Das folgende XAML-Beispiel instanziiert FloatToIntConverter
in seinem Ressourcenwörterbuch:
<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>
Die Werte der Eigenschaften Red
und Green
werden mit einer Binding
-Markuperweiterung angezeigt. Die Blue
-Eigenschaft instanziiert jedoch die Binding
Klasse, um zu zeigen, wie ein expliziter float
-Wert auf die ConverterParameter
-Eigenschaft gesetzt werden kann: