Databindning med felmatchade typer

Slutförd

Ibland matchar inte de data som du använder datatypen för kontrollegenskapen som visar data. Du kan till exempel ha ett penningvärde som lagras i en decimal typ som du vill visa på en Label kontroll, formaterad som en valuta. Ett mer komplicerat exempel skulle vara med väderappen som visas i modulen. En bild ska visas baserat på väderprognosens eller Cloudy uppräkningsvärdetSunny, men du kan inte binda källans uppräkningsvärde till ett måls bildegenskap. I den här lektionen går vi igenom hur du kan konvertera data.

Strängformatering

Ett vanligt typmatchningsfel är en inbyggd typ som du vill visa som en formaterad sträng. Som när du vill visa delar av ett DateTime värde eller om du vill formatera en decimal typ som valuta.

Anta att du vill visa det belopp som ska betalas på en faktura och att du har den här egenskapen för dataobjektet:

public decimal BillAmount { get; set; }

Det belopp som är skyldigt blir 22.0304. Du kan använda två etikettkontroller för att visa text och dollarbeloppet enligt följande kodfragment:

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

Detta matar ut en sträng till användargränssnittet som ser ut som You owe 22.0304 to the bank, men den saknar valutasymbolen och det kan finnas för många eller för få decimaler baserat på den lokala valutan. Normalt bearbetar du värdet som en sträng med formatspecificeraren "C" (eller valuta) i koden, så här:

string formattedBillAmount = string.Format("{0:C}", BillAmount);

Men om du vill använda formatering i databindning måste du antingen låta dataobjektet ange den formaterade strängen som en annan egenskap, eller fånga upp den på något sätt och formatera den själv. Lyckligtvis är .NET MAUI-bindningar ett sätt att formatera strängar med bindningsegenskapen StringFormat . Formatsträngen följer samma regler som String.Format metoden. Omslut formatsträngen med enkla citattecken så att XAML-parsern inte blir förvirrad av klammerparenteserna. Strängformatparametern 0 är egenskapsvärdet som bearbetas av bindningen.

<Label Text="{Binding BillAmount, StringFormat='You owe {0:C} to the bank'}" />

Överväg följande XAML, som visar hur du visar hur du använder båda sätten BillAmount :

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

Följande bild visar vad XAML-utdata producerar på skärmen:

Skärmbild av en .NET MAUI Android-app som visar två olika etikettkontroller med text relaterad till på grund av en faktura. En etiketts text är formaterad med USD-valuta.

XAML med bindningsegenskapen StringFormat är enklare än den andra XAML och du har åtkomst till . NET:s kraftfulla strängformateringssystem.

Konvertering av anpassad typ

Bindningsegenskapen StringFormat är praktisk när du visar ett värde som en sträng, men inte när du vill konvertera något som liknar en eller Image från en Color annan typ. I dessa fall måste du skriva anpassad konverteringskod.

Anta att du uppmanar användaren att välja ett lösenord och att du vill använda en färg i användargränssnittet för att ange lösenordets styrka. Det finns tre nivåer av styrka: svag, bra, stark. Styrkan baseras på hur många tecken som finns i lösenordet. Om du vill ge omedelbar feedback till användaren om deras lösenordsstyrka vill du att bakgrunden till kontrollen Entry som innehåller lösenordet ska ändras baserat på styrkan. Följande bild visar dessa tre styrkenivåer: svaga, bra och starka.

Skärmbild av en .NET MAUI Android-app med tre inmatningskontroller, var och en med en annan färgad bakgrund.

Av de tre postkontrollerna i skärmbilden har den första fyra tecken angivna och har en röd bakgrund. Den andra har nio tecken angivna och har en gul bakgrund. Den senaste inmatningskontrollen har 15 tecken och har en blå bakgrund.

Dessa nivåer tilldelas till Strength uppräkningen:

private enum Strength
{
    Weak,
    Good,
    Strong
}

Ett dataobjekt tilldelas som sidans BindingContext, som innehåller lösenordets styrka med PasswordStrength egenskapen . När användaren skriver in ett lösenord PasswordStrength ändras egenskapen enligt lösenordets längd. Eftersom dataobjektet innehåller PasswordStrength egenskapen binder du den egenskapen till BackgroundColor Entry kontrollens:

<Entry BackgroundColor="{Binding PasswordStrength} ... />

Det finns dock ett problem här. PasswordStrength Är av typen Strength medan BackgroundColor är en Color. Dessa typer är inte kompatibla med varandra. .NET MAUI är ett sätt att åtgärda dessa typmatchningsproblem, bindningens Converter egenskap.

En bindningskonverterare gör precis vad namnet säger, konverterar mellan bindningskällan och målet. Konverterare implementeras via IValueConverter gränssnittet.

Implementera IValueConverter

Du skapar konverteringslogik i en klass som implementerar IValueConverter gränssnittet. Vanligtvis slutar namnen på dessa klasser med namnet Converter för att göra dess syfte tydligt.

Gränssnittet IValueConverter definierar två metoder:

  • Convert– Konverterar från bindningskällans egenskap till bindningsmålets UI-egenskap.

  • ConvertBack– Konverterar från bindningsmålets UI-egenskap tillbaka till bindningskällans egenskap.

    Den här metoden används sällan och används inte i det här scenariot. De flesta konverterare genererar en NotSupportedException för att indikera att den här konverteringen inte stöds.

Här är gränssnittets kontrakt:

public interface IValueConverter
{
    object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture);
    object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture);
}

Kom ihåg att scenariot vi arbetar med är att binda Entry.BackgroundColor egenskapen till dataobjektets PasswordStrength egenskap, vilket är en Strength uppräkning.

<Entry BackgroundColor="{Binding PasswordStrength} ... />

Uppräkningen Strength måste konverteras till en Color. Konverteraren måste därför utvärdera vilket värde som Strength anges och returnera ett annat Color. Följande kod visar den här konverteringen:

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

Nu ska vi gå in på den här koden:

  • Metoden Convert har fyra parametrar. Du kan vanligtvis ignorera de två sista parametrarna om du inte har en specifik anledning att använda dem.
  • Parametern value innehåller det inkommande värdet. I det här exemplet är det ett Strength uppräkningsvärde.
  • Parametern targetType ignoreras. Men du kan använda den här parametern för att verifiera att den typ av egenskap som konverteraren används med är en Color. Detta utelämnas i det här exemplet för enkelhetens skull.
  • Ett växeluttryck används för att returnera en annan färg baserat på Strength värdet.

Använda konverteraren i XAML

När konverterarklassen har skapats måste du skapa en instans av den och referera till den i bindningen. Standardsättet för att instansiera konverteraren finns i rotelementets resursordlista.

Mappa först ett XML-namnområde till .NET-namnområdet som innehåller konverteraren. I följande kodexempel cvt mappar XML-namnområdet till MyProject.Converters .NET-namnområdet:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cvt="clr-namespace:MyProject.Converters"
             ...

Skapa sedan en instans i 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>

Nu finns en instans av konverteraren i resursordlistan med nyckeln StrengthToColorConverter, som råkar vara samma namn som typen. Detta är ett typiskt sätt att namnge konverterare, eftersom du vanligtvis bara har en enda konverterare som du återanvänder i hela XAML. Om du av någon anledning behöver flera konverterarinstanser måste nycklarna vara olika mellan dem.

Slutligen refererar du till konverteraren på bindningen. Eftersom konverteraren finns i en resursordlista använder du markeringstillägget {StaticResource} för att referera till det. Konverteraren tilldelas till bindningsegenskapen Converter :

<Entry BackgroundColor="{Binding PasswordStrength, Converter={StaticResource StrengthToColorConverter}}" ... />

Kontrollera dina kunskaper

1.

Vilken är den bästa metoden för att visa och formatera ett värde som en sträng i databindningen?

2.

Vilken typ används vid databindningskonvertering?