Datenbindung mit nicht übereinstimmenden Typen
Manchmal stimmen die von Ihnen 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“ (Currency; Währung) im Code:
string formattedBillAmount = string.Format("{0:C}", BillAmount);
Wenn Sie jedoch Formatierung in der Datenbindung verwenden möchten, müssen Sie entweder festlegen, dass Ihnen das Datenobjekt die formatierte Zeichenfolge als eine andere Eigenschaft zur Verfügung stellt, 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, der von der Bindung verarbeitet wird.
<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 möchten eine Farbe auf der Benutzeroberfläche verwenden, um die Sicherheit des Kennworts 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} ... />
Allerdings gibt es hier ein Problem. 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 die Eigenschaft der Bindungsquelle in die Benutzeroberflächeneigenschaft des Bindungsziels.ConvertBack
: Konvertiert die Benutzeroberflächeneigenschaft 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
NotSupportedException
aus, 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 in dem von uns verwendeten Szenario die Eigenschaft Entry.BackgroundColor
an die Eigenschaft PasswordStrength
des Datenobjekts gebunden wird, bei der es sich um eine Strength
-Enumeration handelt.
<Entry BackgroundColor="{Binding PasswordStrength} ... />
Die Strength
-Enumeration muss in eine Farbe (Color
) konvertiert werden. Der Konverter muss also auswerten, welcher Strength
-Wert bereitgestellt wurde, und einen anderen Color
-Wert 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();
}
Nachstehend wird dieser Code nun aufgeschlüsselt:
- 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
value
enthält den eingehenden Wert. In diesem Beispiel handelt es sich um einen Enumerationswert vom TypStrength
. - Der Parameter
targetType
wird ignoriert. Sie können mithilfe dieses Parameters jedoch überprüfen, ob der Typ der Eigenschaft, mit der der Konverter verwendet wird, eine Farbe (Color
) ist. Dies wird in diesem Beispiel der Einfachheit halber weggelassen. - Ein Switch-Ausdruck wird verwendet, um basierend auf dem
Strength
-Wert eine andere Farbe zurückzugeben.
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 enthält das Ressourcenverzeichnis eine Instanz des Konverters mit dem Schlüssel StrengthToColorConverter
, der mit dem Namen des Typs identisch 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 Ressourcenverzeichnis befindet, verwenden Sie die Markuperweiterung {StaticResource}
, um auf ihn zu verweisen. Der Konverter wird der Bindungseigenschaft Converter
zugewiesen:
<Entry BackgroundColor="{Binding PasswordStrength, Converter={StaticResource StrengthToColorConverter}}" ... />