Udostępnij za pośrednictwem


Konwertery wartości powiązania

Browse sample. Przeglądanie przykładu

Powiązania danych interfejsu użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI) zwykle przesyłają dane z właściwości źródłowej do właściwości docelowej, a w niektórych przypadkach z właściwości docelowej do właściwości źródłowej. Ten transfer jest prosty, gdy właściwości źródłowe i docelowe są tego samego typu lub gdy jeden typ można przekonwertować na inny typ za pomocą niejawnej konwersji. Jeśli tak nie jest, należy przeprowadzić konwersję typu.

W artykule Formatowanie ciągu pokazano, jak można użyć StringFormat właściwości powiązania danych, aby przekonwertować dowolny typ na ciąg. W przypadku innych typów konwersji należy napisać wyspecjalizowany kod w klasie, która implementuje IValueConverter interfejs. Klasy implementujące IValueConverter są nazywane konwerterami wartości, ale są również często określane jako konwertery powiązań lub konwertery wartości powiązań.

Konwertery wartości powiązania

Załóżmy, że chcesz zdefiniować powiązanie danych, w którym właściwość źródłowa jest typu int , ale właściwość docelowa boolto . To powiązanie danych ma spowodować wygenerowanie false wartości, gdy źródło całkowite jest równe 0 i true w przeciwnym razie. Można to osiągnąć za pomocą klasy, która implementuje IValueConverter interfejs:

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

Następnie należy ustawić wystąpienie tej klasy na Converter właściwość Binding klasy lub Converter właściwość Binding rozszerzenia znaczników. Ta klasa staje się częścią powiązania danych.

Metoda jest wywoływana Convert , gdy dane są przesyłane ze źródła do obiektu docelowego w OneWay pliku lub TwoWay powiązaniach. Parametr value jest obiektem lub wartością ze źródła powiązania danych. Metoda musi zwrócić wartość typu obiektu docelowego powiązania danych. Pokazana tutaj metoda rzutuje value parametr na wartość , int a następnie porównuje go z wartością 0 dla wartości zwracanej bool .

Metoda jest wywoływana ConvertBack , gdy dane są przesyłane z obiektu docelowego do źródła w TwoWay pliku lub OneWayToSource powiązania. ConvertBack wykonuje odwrotną konwersję: zakłada value , że parametr jest z bool obiektu docelowego i konwertuje go na wartość zwracaną int dla źródła.

Uwaga

Jeśli powiązanie danych zawiera StringFormat również ustawienie, konwerter wartości jest wywoływany, zanim wynik zostanie sformatowany jako ciąg.

W poniższym przykładzie pokazano, jak używać tego konwertera wartości w powiązaniu danych:

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

W tym przykładzie wystąpienie obiektu IntToBoolConverter jest tworzone w słowniku zasobów strony. Następnie odwołuje StaticResource się do niego rozszerzenie znaczników, aby ustawić Converter właściwość w dwóch powiązaniach danych. Bardzo często można udostępniać konwertery danych między wieloma powiązaniami danych na stronie. Jeśli konwerter wartości jest używany na wielu stronach aplikacji, możesz utworzyć wystąpienie w słowniku zasobów na poziomie aplikacji.

W tym przykładzie pokazano typową potrzebę Button wykonania operacji na podstawie tekstu, który użytkownik wpisze w Entry widoku. Właściwość Text każdego z nich Entry jest inicjowana do pustego ciągu, ponieważ Text właściwość jest null domyślnie, a powiązanie danych nie będzie działać w takim przypadku. Jeśli nic nie zostało wpisane w obiekcie Entry, Button element powinien być wyłączony. Każdy z nich Button zawiera powiązanie danych dla jego IsEnabled właściwości. Źródło powiązania danych jest właściwością Length Text odpowiedniego Entryelementu . Jeśli ta Length właściwość nie jest równa 0, konwerter wartości zwraca true wartość i Button parametr jest włączony:

Enable buttons.

Uwaga

Jeśli wiesz, że konwerter wartości będzie używany tylko w OneWay powiązaniach, ConvertBack metoda może po prostu zwrócić nullwartość .

Metoda przedstawiona Convert powyżej zakłada, że value argument jest typu int , a zwracana wartość musi być typu bool. Podobnie metoda zakłada, ConvertBack że value argument jest typu bool , a zwracana wartość to int. Jeśli tak nie jest, wystąpi wyjątek środowiska uruchomieniowego.

Można napisać konwertery wartości, aby być bardziej uogólnione i zaakceptować kilka różnych typów danych. Metody Convert i ConvertBack mogą używać as operatorów lub is z parametrem value lub może wywołać GetType ten parametr, aby określić jego typ, a następnie zrobić coś odpowiedniego. Oczekiwany typ zwracanej wartości każdej metody jest podawany targetType przez parametr . Czasami konwertery wartości są używane z powiązaniami danych różnych typów docelowych. W takim przypadku konwerter wartości może użyć argumentu targetType do przeprowadzenia konwersji dla poprawnego typu.

Jeśli wykonywana konwersja różni się w różnych kulturach, użyj parametru culture w tym celu.

Właściwości konwertera powiązań

Klasy konwertera wartości mogą mieć właściwości i parametry ogólne. Następujący konwerter wartości konwertuje element bool ze źródła na obiekt typu T dla obiektu docelowego:

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

W poniższym przykładzie pokazano, jak ten konwerter może służyć do wyświetlania Switch wartości widoku. Mimo że często tworzy się wystąpienia konwerterów wartości jako zasobów w słowniku zasobów, w tym przykładzie pokazano alternatywę. W tym miejscu każdy konwerter wartości jest tworzone między tagami Binding.Converter właściwości-element. Element x:TypeArguments wskazuje argument ogólny i TrueObject FalseObject są ustawione na obiekty tego typu:

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

W tym przykładzie w ostatnim z trzech Switch i Label par ogólny argument jest ustawiony na Style, a całe Style obiekty są udostępniane dla wartości TrueObject i FalseObject. Zastępują one niejawny styl Label ustawiania w słowniku zasobów, więc właściwości w tym stylu są jawnie przypisywane do obiektu Label. Przełączenie Switch przyczyn odpowiadających Label zmianie:

Switch indicators.

Uwaga

Można również używać wyzwalaczy do implementowania zmian w interfejsie użytkownika na podstawie innych widoków. Aby uzyskać więcej informacji, zobacz Triggers (Wyzwalacze).

Parametry konwertera powiązań

Klasa Binding definiuje ConverterParameter właściwość, a Binding rozszerzenie znaczników definiuje ConverterParameter również właściwość. Jeśli ta właściwość jest ustawiona, wartość jest przekazywana do Convert metod i ConvertBack jako argumentu parameter . Nawet jeśli wystąpienie konwertera wartości jest współużytkowane między kilkoma powiązaniami danych, ConverterParameter może to być inne, aby wykonać różne konwersje.

Użycie ConverterParameter właściwości można zademonstrować za pomocą programu wyboru kolorów. W poniższym przykładzie RgbColorViewModelpokazano , który ma trzy właściwości typu float o nazwie Red, Greeni Blue który używa do konstruowania Color wartości:

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

Wartości Redwłaściwości , Greeni Blue mogą mieścić się w zakresie od 0 do 1. Jednak wolisz, aby składniki mogły być wyświetlane jako dwucyfrowe wartości szesnastkowe. Aby wyświetlić je jako wartości szesnastkowe w języku XAML, należy je pomnożyć przez 255, przekonwertować na liczbę całkowitą, a następnie sformatować za pomocą specyfikacji "X2" we StringFormat właściwości . Pomnożenie przez 255 i konwertowanie na liczbę całkowitą może być wykonywane przez konwerter wartości. Aby konwerter wartości był tak uogólniony, jak to możliwe, współczynnik mnożenia można określić za pomocą ConverterParameter właściwości , co oznacza, że wprowadza Convert metody i ConvertBack jako parameter argument:

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

W tym przykładzie Convert metoda konwertuje wartość z wartości na wartość float int parameter na . Metoda ConvertBack dzieli argument liczby całkowitej value przez parameter i zwraca float wynik.

Typ argumentu parameter może się różnić w zależności od tego, czy powiązanie danych jest zdefiniowane w języku XAML, czy w kodzie. ConverterParameter Jeśli właściwość elementu Binding jest ustawiona w kodzie, prawdopodobnie zostanie ustawiona wartość liczbowa:

binding.ConverterParameter = 255;

Właściwość ConverterParameter jest typu Object, więc kompilator języka C# interpretuje literał 255 jako liczbę całkowitą i ustawia właściwość na wartość tej wartości.

Jednak w języku XAML ConverterParameter prawdopodobnie zostanie ustawiona następująco:

<Label Text="{Binding Red,
                      Converter={StaticResource doubleToInt},
                      ConverterParameter=255,
                      StringFormat='Red = {0:X2}'}" />

Chociaż 255 wygląda jak liczba, ponieważ ConverterParameter jest typu Object, analizator XAML traktuje 255 jako ciąg. Z tego powodu konwerter wartości zawiera oddzielną GetParameter metodę, która obsługuje przypadki parameter bycia typem float, intlub string.

Poniższy przykład XAML tworzy wystąpienie FloatToIntConverter w słowniku zasobów:

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

Wartości Red właściwości i Green są wyświetlane z Binding rozszerzeniem znaczników. Właściwość Blue tworzy jednak wystąpienie Binding klasy, aby zademonstrować, w jaki sposób można ustawić jawną float wartość na ConverterParameter właściwość:

RGB color selector.