Powiązanie danych z niezgodnymi typami

Ukończone

Czasami używane dane nie są zgodne z typem danych właściwości kontrolki wyświetlającej dane. Na przykład możesz mieć wartość pieniężną przechowywaną decimal w typie, który ma być wyświetlany w kontrolce Label sformatowanej jako waluta. Bardziej skomplikowanym przykładem może być aplikacja pogodowa przedstawiona w module. Obraz ma być wyświetlany na podstawie wartości wyliczenia lub Cloudy prognozy Sunny pogody, ale nie można powiązać wartości wyliczenia źródła z właściwością obrazu obiektu docelowego. W tej lekcji przedstawiono sposoby konwertowania danych.

Formatowanie ciągu

Typowa niezgodność typów to typ wewnętrzny, który ma być wyświetlany jako sformatowany ciąg. Podobnie jak w przypadku, gdy chcesz wyświetlić części DateTime wartości lub chcesz sformatować typ jako walutę decimal .

Załóżmy, że chcesz wyświetlić kwotę należną na rachunku i masz tę właściwość w obiekcie danych:

public decimal BillAmount { get; set; }

Kwota należna wynosi 22,0304. Możesz użyć dwóch kontrolek etykiet, aby wyświetlić tekst i kwotę dolara, jak pokazano w poniższym fragmencie kodu:

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

Spowoduje to wyprowadzenie ciągu do interfejsu użytkownika, który wygląda następująco: You owe 22.0304 to the bank, ale brakuje symbolu waluty i może być zbyt wiele lub zbyt mało miejsc dziesiętnych na podstawie waluty lokalnej. Zwykle wartość jest przetwarzana jako ciąg z specyfikatorem formatu "C" (lub waluty) w kodzie, w następujący sposób:

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

Jednak aby używać formatowania w powiązaniu danych, musisz mieć obiekt danych, aby zapewnić ten sformatowany ciąg jako inną właściwość lub przechwycić go jakoś i sformatować samodzielnie. Na szczęście powiązania MAUI platformy .NET umożliwiają formatowanie ciągów za StringFormat pomocą właściwości powiązania. Ciąg formatu jest zgodny z tymi samymi regułami co String.Format metoda. Ujmij ciąg formatu w pojedynczych cudzysłowach, aby analizator XAML nie był mylony przez nawiasy klamrowe. Parametr 0 formatu ciągu to wartość właściwości przetworzona przez powiązanie.

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

Rozważmy następujący kod XAML, który pokazuje, jak używać BillAmount obu sposobów:

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

Na poniższej ilustracji przedstawiono dane wyjściowe XAML generowane na ekranie:

Zrzut ekranu przedstawiający aplikację .NET MAUI dla systemu Android z dwoma różnymi kontrolkami etykiet z tekstem powiązanym z powodu rachunku. Tekst jednej etykiety jest sformatowany przy użyciu waluty USD.

Język XAML używający StringFormat właściwości powiązania jest prostszy niż inny kod XAML i masz dostęp do elementu . Zaawansowany system formatowania ciągów platformy NET.

Konwersja typu niestandardowego

StringFormat Właściwość powiązania jest wygodna podczas wyświetlania wartości jako ciągu, ale nie wtedy, gdy chcesz przekonwertować coś takiego jak lub Color Image z innego typu. W takich przypadkach należy napisać niestandardowy kod konwersji.

Załóżmy, że monitujesz użytkownika o wybranie hasła i chcesz użyć koloru w interfejsie użytkownika, aby wskazać siłę hasła. Istnieją trzy poziomy siły: słaby, dobry, silny. Siła zależy od liczby znaków w haśle. Aby przekazać użytkownikowi natychmiastową opinię na temat siły hasła, chcesz, aby tło Entry kontrolki zawierającej hasło zmieniło się na podstawie siły. Na poniższej ilustracji przedstawiono te trzy poziomy siły: słabe, dobre i silne.

Zrzut ekranu przedstawiający aplikację .NET MAUI dla systemu Android z trzema kontrolkami wprowadzania, z których każdy ma inne kolorowe tło.

Spośród trzech kontrolek wprowadzania na zrzucie ekranu pierwszy zawiera cztery znaki i zawiera czerwone tło. Drugi zawiera dziewięć znaków i zawiera żółte tło. Ostatnia kontrolka wpisu ma 15 znaków i zawiera niebieskie tło.

Te poziomy są przypisywane do Strength wyliczenia:

private enum Strength
{
    Weak,
    Good,
    Strong
}

Obiekt danych jest przypisywany jako obiekt strony BindingContext, który zawiera siłę hasła z właściwością PasswordStrength . Ponieważ użytkownik wpisuje hasło, PasswordStrength właściwość jest zmieniana zgodnie z długością hasła. Ponieważ obiekt danych zawiera PasswordStrength właściwość , należy powiązać właściwość z BackgroundColor kontrolką Entry :

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

Istnieje jednak problem. Parametr PasswordStrength jest typu Strength , a BackgroundColor element to Color. Te typy nie są ze sobą zgodne. Program .NET MAUI umożliwia rozwiązywanie problemów z niezgodnością typów, właściwością powiązania Converter .

Konwerter powiązań robi tylko to, co jego nazwa mówi, konwertuje między źródłem powiązania a elementem docelowym. Konwertery są implementowane za pośrednictwem interfejsu IValueConverter .

Implementowanie elementu IValueConverter

Logikę konwersji można utworzyć w klasie, która implementuje IValueConverter interfejs. Zazwyczaj nazwy tych klas kończą się nazwą Converter , aby jej przeznaczenie było jasne.

Interfejs IValueConverter definiuje dwie metody:

  • Convert— konwertuje właściwość źródła powiązania na właściwość interfejsu użytkownika obiektu docelowego powiązania.

  • ConvertBack— konwertuje właściwość interfejsu użytkownika elementu docelowego powiązania z powrotem na właściwość źródła powiązania.

    Ta metoda jest rzadko używana i nie jest używana w tym scenariuszu. Większość konwerterów zgłasza wartość , NotSupportedException aby wskazać, że ta konwersja nie jest obsługiwana.

Oto kontrakt interfejsu:

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

Pamiętaj, że scenariusz, z którym pracujemy, wiąże Entry.BackgroundColor właściwość z właściwością obiektu PasswordStrength danych, która jest wyliczeniem Strength .

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

Wyliczenie Strength musi zostać przekonwertowane na .Color Dlatego konwerter musi ocenić, która Strength wartość jest podana, i zwrócić inną Colorwartość . Poniższy kod demonstruje tę konwersję:

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

Przeanalizujmy ten kod:

  • Metoda Convert ma cztery parametry. Można zazwyczaj odrzucić dwa ostatnie parametry, chyba że masz określony powód do ich użycia.
  • Parametr value zawiera wartość przychodzącą. W tym przykładzie Strength jest to wartość wyliczenia.
  • Parametr targetType jest ignorowany. Można jednak użyć tego parametru, aby sprawdzić, czy typ właściwości, z którą jest używany konwerter, to Color. W tym przykładzie pominięto to dla uproszczenia.
  • Wyrażenie przełącznika służy do zwracania innego koloru na Strength podstawie wartości.

Używanie konwertera w języku XAML

Po utworzeniu klasy konwertera należy utworzyć wystąpienie i odwołać się do niego w powiązaniu. Standardowy sposób tworzenia wystąpienia konwertera znajduje się w słowniku zasobów elementu głównego.

Najpierw zamapuj przestrzeń nazw XML na przestrzeń nazw platformy .NET zawierającą konwerter. W poniższym przykładzie cvt kodu przestrzeń nazw XML mapuje się na przestrzeń nazw platformy MyProject.Converters .NET:

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

Następnie utwórz wystąpienie w pliku 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>

Teraz wystąpienie konwertera znajduje się w słowniku zasobów z kluczem StrengthToColorConverter, który ma taką samą nazwę jak typ. Jest to typowy sposób nazewnictwa konwerterów, ponieważ zwykle masz tylko jeden konwerter używany ponownie w całym języku XAML. Jeśli z jakiegoś powodu wymagane jest wiele wystąpień konwertera, klucze muszą być różne między nimi.

Na koniec odwołaj się do konwertera w powiązaniu. Ponieważ konwerter znajduje się w słowniku zasobów, należy użyć {StaticResource} rozszerzenia znaczników, aby się do niego odwoływać. Konwerter jest przypisywany Converter do właściwości powiązania:

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

Sprawdź swoją wiedzę

1.

Aby wyświetlić i sformatować wartość jako ciąg w powiązaniu danych, co jest najlepszym rozwiązaniem?

2.

Który typ jest używany w konwersji powiązania danych?