Datenbindung mit nicht übereinstimmenden Typen
- 10 Minuten
Manchmal stimmen die verwendeten Daten nicht mit dem Datentyp der Steuerelementeigenschaft überein, die die Daten anzeigt. Sie können beispielsweise einen Geldwert in einem decimal-Typ speichern, der auf einem Label-Steuerelement als Währung formatiert angezeigt werden soll. Ein komplizierteres Beispiel wäre die in diesem Modul vorgestellte Wetter-App. Basierend auf dem Enumerationswert Sunny oder Cloudy der Wettervorhersage soll ein Bild angezeigt werden. Sie können den Enumerationswert der Quelle jedoch nicht an die Bildeigenschaft des Ziels binden. In dieser Lerneinheit werden die Möglichkeiten zum Konvertieren von Daten untersucht.
Zeichenfolgenformatierung
Ein häufiger Typkonflikt ist ein intrinsischer Typ, den Sie als formatierte Zeichenfolge anzeigen möchten. Dies entspricht etwa dem Anzeigen von Teilen eines DateTime-Werts oder dem Formatieren eines decimal-Typs als Währung.
Angenommen, Sie möchten den fälligen Betrag auf einer Rechnung anzeigen, und Sie haben die folgende Eigenschaft für Ihr Datenobjekt:
public decimal BillAmount { get; set; }
Der geschuldete Betrag beträgt 22,0304. Sie können zwei Label-Steuerelemente verwenden, um Text und den Dollarbetrag anzuzeigen, wie im folgenden Codeschnipsel gezeigt:
<HorizontalStackLayout>
<Label Text="You owe" Margin="0,0,5,0" />
<Label Text="{Binding BillAmount}" />
<Label Text="to the bank" Margin="5,0,0,0" />
</HorizontalStackLayout>
Dadurch wird eine Zeichenfolge an die Benutzeroberfläche ausgegeben, die wie You owe 22.0304 to the bank aussieht. Es fehlt jedoch das Währungssymbol, und es gibt möglicherweise zu viele oder zu wenige Dezimalstellen basierend auf der lokalen Währung. Normalerweise verarbeiten Sie den Wert wie folgt als Zeichenfolge mit dem Formatbezeichner "C" (oder Währungsformat) im Code:
string formattedBillAmount = string.Format("{0:C}", BillAmount);
Um jedoch formatierungen in der Datenbindung zu verwenden, müssen Sie entweder über das Datenobjekt verfügen, die formatierte Zeichenfolge für Sie als andere Eigenschaft bereitstellen, oder sie irgendwie abfangen und selbst formatieren. Glücklicherweise bieten .NET MAUI-Bindungen eine Möglichkeit zum Formatieren von Zeichenfolgen mit der Bindungseigenschaft StringFormat. Die Formatzeichenfolge folgt denselben Regeln wie die String.Format-Methode. Schließen Sie die Formatzeichenfolge in einfache Anführungszeichen ein, damit der XAML-Parser nicht durch die geschweiften Klammern verwirrt wird. Der Zeichenfolgenformatparameter 0 ist der Eigenschaftswert, den die Bindungsprozesse verarbeiten.
<Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />
Betrachten Sie den folgenden XAML-Code, der die Anzeige von BillAmount mithilfe beider Methoden veranschaulicht:
<VerticalStackLayout Padding="10">
<HorizontalStackLayout>
<Label Text="You owe" Margin="0,0,5,0" />
<Label Text="{Binding BillAmount}" />
<Label Text="to the bank" Margin="5,0,0,0" />
</HorizontalStackLayout>
<HorizontalStackLayout>
<Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />
</HorizontalStackLayout>
</VerticalStackLayout>
Die folgende Abbildung zeigt, was die XAML-Ausgabe auf dem Bildschirm erzeugt:
Der XAML-Code mit der Bindungseigenschaft StringFormat ist einfacher als der andere XAML-Code, und Sie haben Zugriff auf die das leistungsstarke Zeichenfolgenformatierungssystem von NET.
Benutzerdefinierte Typkonvertierung
Die Bindungseigenschaft StringFormat eignet sich für das Anzeigen eines Werts als Zeichenfolge, aber nicht, wenn Sie ein Element wie Color oder Image aus einem anderen Typ konvertieren möchten. In diesen Fällen müssen Sie benutzerdefinierten Konvertierungscode schreiben.
Angenommen, Sie fordern den Benutzer auf, ein Kennwort auszuwählen, und Sie möchten eine Farbe in der Benutzeroberfläche verwenden, um die Kennwortstärke anzugeben. Es gibt drei Stufen bei der Sicherheit: unsicher, gut, sicher. Die Sicherheit basiert auf der Anzahl der Zeichen im Kennwort. Um dem Benutzer umgehend Feedback zur Kennwortsicherheit zu geben, soll sich der Hintergrund des Entry-Steuerelements, das das Kennwort enthält, basierend auf der Sicherheit ändern. Die folgende Abbildung zeigt diese drei Stufen der Sicherheit: unsicher, gut und sicher.
Von den drei Entry-Steuerelementen auf dem Screenshot verfügt das erste über vier eingegebene Zeichen und einen roten Hintergrund. Das zweite enthält neun eingegebene Zeichen und verfügt über einen gelben Hintergrund. Das letzte Entry-Steuerelement hat 15 Zeichen und einen blauen Hintergrund.
Diese Stufen werden der Strength-Enumeration zugewiesen:
private enum Strength
{
Weak,
Good,
Strong
}
Ein Datenobjekt wird als Bindungskontext (BindingContext) der Seite zugewiesen, der mit der PasswordStrength-Eigenschaft die Sicherheit des Kennworts enthält. Wenn der Benutzer ein Kennwort eingibt, wird die PasswordStrength-Eigenschaft entsprechend der Länge des Kennworts geändert. Da das Datenobjekt die PasswordStrength-Eigenschaft enthält, binden Sie diese Eigenschaft an das BackgroundColor-Element des Entry-Steuerelements:
<Entry BackgroundColor="{Binding PasswordStrength} ... />
Es gibt jedoch ein Problem hier.
PasswordStrength ist vom Typ Strength, BackgroundColor hingegen eine Farbe (Color). Diese Typen sind nicht miteinander kompatibel. .NET MAUI bietet eine Möglichkeit, diese Typenkonfliktprobleme zu beheben: die Eigenschaft Converter der Bindung.
Ein Bindungskonverter macht genau das, was sein Name sagt: Er führt eine Konvertierung zwischen der Bindungsquelle und dem Bindungsziel durch. Konverter werden über die IValueConverter-Schnittstelle implementiert.
Implementieren von IValueConverter
Sie erstellen Ihre Konvertierungslogik in einer Klasse, die die IValueConverter-Schnittstelle implementiert. In der Regel enden die Namen dieser Klassen mit dem Namen Converter, um ihren Zweck deutlich zu machen.
In der IValueConverter-Schnittstelle sind zwei Methoden definiert:
Convert: Konvertiert von der Eigenschaft der Bindungsquelle in die UI-Eigenschaft des Bindungsziels.ConvertBack: Konvertiert von der UI-Eigenschaft des Bindungsziels zurück in die Eigenschaft der Bindungsquelle.Diese Methode wird selten und in diesem Szenario nicht verwendet. Die meisten Konverter lösen eine Ausnahme vom Typ
NotSupportedExceptionaus, um anzugeben, dass diese Konvertierung nicht unterstützt wird.
Dies ist der Schnittstellenvertrag:
public interface IValueConverter
{
object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture);
object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture);
}
Denken Sie daran, dass das Szenario, mit dem wir arbeiten, die Entry.BackgroundColor Eigenschaft an die Eigenschaft des Datenobjekts PasswordStrength binden, bei der es sich um eine Strength Enumeration handelt.
<Entry BackgroundColor="{Binding PasswordStrength} ... />
Die Strength Aufzählung muss in einen Colorkonvertiert werden, sodass der Konverter auswerten muss, welcher Strength Wert bereitgestellt wird, und einen anderen Colorwert zurückgeben. Der folgende Code veranschaulicht diese Konvertierung:
namespace MyProject.Converters;
class StrengthToColorConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return (Strength)value! switch
{
Strength.Weak => Colors.OrangeRed,
Strength.Good => Colors.Yellow,
Strength.Strong => Colors.LightBlue,
_ => Colors.LightBlue
};
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
Lassen Sie uns diesen Code aufschlüsseln:
- Die
Convert-Methode hat vier Parameter. Sie können die letzten beiden Parameter in der Regel verwerfen, es sei denn, Sie haben einen bestimmten Grund, sie zu verwenden. - Der Parameter
valueenthält den eingehenden Wert. In diesem Beispiel handelt es sich um einen Enumerationswert vom TypStrength. - Der
targetTypeParameter wird ignoriert, Aber Sie können diesen Parameter verwenden, um zu überprüfen, ob der Typ der Eigenschaft, mit der der Konverter verwendet wird, einColor. Dies wird in diesem Beispiel der Einfachheit halber weggelassen. - Ein Schalterausdruck gibt basierend auf dem
StrengthWert eine andere Farbe zurück.
Verwenden des Konverters in XAML
Nachdem die Konverterklasse erstellt wurde, müssen Sie eine Instanz davon erstellen und in der Bindung darauf verweisen. Die gängigste Methode, den Konverter zu instanziieren, ist im Ressourcenverzeichnis des Stammelements.
Ordnen Sie zunächst dem .NET-Namespace, der den Konverter enthält, einen XML-Namespace zu. Im folgenden Codebeispiel wird der XML-Namespace cvt dem .NET-Namespace MyProject.Converters zugeordnet:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cvt="clr-namespace:MyProject.Converters"
...
Erstellen Sie als Nächstes eine Instanz in ContentPage.Resources:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cvt="clr-namespace:MyProject.Converters"
x:Class="MyProject.PasswordExample">
<ContentPage.Resources>
<cvt:StrengthToColorConverter x:Key="StrengthToColorConverter" />
</ContentPage.Resources>
Jetzt befindet sich eine Instanz des Konverters im Ressourcenwörterbuch mit dem Schlüssel StrengthToColorConverter, was derselbe Name wie der Typ ist. Dies ist eine typische Methode zum Benennen von Konvertern, da Sie im Allgemeinen nur über einen einzelnen Konverter verfügen, den Sie im gesamten XAML-Code wiederverwenden. Wenn Sie aus irgendeinem Grund mehrere Konverterinstanzen benötigten, müssen ihre Schlüssel unterschiedlich sein.
Verweisen Sie abschließend auf den Konverter für die Bindung. Da sich der Konverter in einem Ressourcenwörterbuch befindet, verwenden Sie die {StaticResource} Markuperweiterung, um darauf zu verweisen. Der Konverter wird der Bindungseigenschaft Converter zugewiesen:
<Entry BackgroundColor="{Binding PasswordStrength, Converter={StaticResource StrengthToColorConverter}}" ... />