Udostępnij za pośrednictwem


Xamarin.Forms Konwertery wartości powiązania

Powiązania danych 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. (Platforma uniwersalna systemu Windows zawiera podobną klasę o nazwie IValueConverter w Windows.UI.Xaml.Data przestrzeni nazw, ale znajduje się ona IValueConverter w Xamarin.Forms przestrzeni nazw). 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ń.

IValueConverter, interfejs

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

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.

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

Na stronie Włącz przyciski w przykładzie pokazano, jak używać tego konwertera wartości w powiązaniu danych. Element IntToBoolConverter jest tworzone w słowniku zasobów strony. Następnie jest przywołyny z StaticResource rozszerzeniem 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:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.EnableButtonsPage"
             Title="Enable Buttons">
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:IntToBoolConverter x:Key="intToBool" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <Entry x:Name="entry1"
               Text=""
               Placeholder="enter search term"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Search"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                IsEnabled="{Binding Source={x:Reference entry1},
                                    Path=Text.Length,
                                    Converter={StaticResource intToBool}}" />

        <Entry x:Name="entry2"
               Text=""
               Placeholder="enter destination"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Submit"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                IsEnabled="{Binding Source={x:Reference entry2},
                                    Path=Text.Length,
                                    Converter={StaticResource intToBool}}" />
    </StackLayout>
</ContentPage>

Jeśli konwerter wartości jest używany na wielu stronach aplikacji, możesz utworzyć wystąpienie w słowniku zasobów w pliku App.xaml .

Strona Włącz przyciski pokazuje typową potrzebę Button wykonania operacji na podstawie tekstu, który użytkownik wpisze w Entry widoku. 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ą LengthText 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:

Włącz przyciski

Zwróć uwagę, że Text właściwość w każdej Entry z nich jest inicjowana do pustego ciągu. Właściwość Text jest null domyślnie, a powiązanie danych nie będzie działać w takim przypadku.

Niektóre konwertery wartości są napisane specjalnie dla konkretnych aplikacji, podczas gdy inne są uogólnione. 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 niejawnie 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; 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. Argument parameter do Convert i ConvertBack jest omówiony w dalszej części tego artykułu.

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

Klasy konwertera wartości mogą mieć właściwości i parametry ogólne. Ten konkretny 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 { set; get; }

    public T FalseObject { set; get; }

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

Na stronie Wskaźniki przełącznika pokazano, jak można go użyć do wyświetlania Switch wartości widoku. Chociaż często tworzy się wystąpienia konwerterów wartości jako zasobów w słowniku zasobów, ta strona przedstawia alternatywę: Każdy konwerter wartości jest tworzony między tagami Binding.Converter właściwości-element. Element x:TypeArguments wskazuje argument ogólny i TrueObjectFalseObject są ustawione na obiekty tego typu:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.SwitchIndicatorsPage"
             Title="Switch Indicators">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="18" />
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>

            <Style TargetType="Switch">
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <StackLayout Orientation="Horizontal"
                     VerticalOptions="CenterAndExpand">
            <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="CenterAndExpand">
            <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="CenterAndExpand">
            <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 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:

Wskaźniki przełącznika

Istnieje również możliwość zaimplementowania Triggers podobnych zmian w interfejsie użytkownika na podstawie innych widoków.

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ć nieco różne konwersje.

Korzystanie z programu ConverterParameter jest pokazane za pomocą programu wyboru kolorów. W tym przypadku element RgbColorViewModel ma trzy właściwości typu double 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 double Red
    {
        set
        {
            if (color.R != value)
            {
                Color = new Color(value, color.G, color.B);
            }
        }
        get
        {
            return color.R;
        }
    }

    public double Green
    {
        set
        {
            if (color.G != value)
            {
                Color = new Color(color.R, value, color.B);
            }
        }
        get
        {
            return color.G;
        }
    }

    public double Blue
    {
        set
        {
            if (color.B != value)
            {
                Color = new Color(color.R, color.G, value);
            }
        }
        get
        {
            return color.B;
        }
    }

    public Color 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);
            }
        }
        get
        {
            return color;
        }
    }

    public string Name
    {
        private set
        {
            if (name != value)
            {
                name = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
            }
        }
        get
        {
            return name;
        }
    }
}

Zakres Redwłaściwości , Greeni Blue z zakresu 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 . Pierwsze dwa zadania (mnożenie przez 255 i konwertowanie na liczbę całkowitą) można obsłużyć 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 DoubleToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (int)Math.Round((double)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 double)
            return (double)parameter;

        else if (parameter is int)
            return (int)parameter;

        else if (parameter is string)
            return double.Parse((string)parameter);

        return 1;
    }
}

Funkcja Convert konwertuje wartość z wartości na wartość ConvertBackparameterintdouble , a argument parameter liczby całkowitej value dzieli wartość i zwraca double wynik. (W programie pokazanym poniżej konwerter wartości jest używany tylko w połączeniu z formatowaniem parametrów, więc ConvertBack nie jest używany).

Typ argumentu parameter może się różnić w zależności od tego, czy powiązanie danych jest zdefiniowane w kodzie, czy XAML. 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}'}" />

255 wygląda jak liczba, ale ze względu ConverterParameter na typ Object, analizator XAML traktuje 255 jako ciąg.

Z tego powodu konwerter wartości pokazany powyżej zawiera oddzielną GetParameter metodę, która obsługuje przypadki parameter bycia typem double, intlub string.

Strona Selektor kolorów RGB tworzy wystąpienie DoubleToIntConverter w słowniku zasobów po definicji dwóch niejawnych stylów:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.RgbColorSelectorPage"
             Title="RGB Color Selector">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Slider">
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>

            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>

            <local:DoubleToIntConverter x:Key="doubleToInt" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <StackLayout.BindingContext>
            <local:RgbColorViewModel Color="Gray" />
        </StackLayout.BindingContext>

        <BoxView Color="{Binding Color}"
                 VerticalOptions="FillAndExpand" />

        <StackLayout Margin="10, 0">
            <Label Text="{Binding Name}" />

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

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

            <Slider Value="{Binding Blue}" />
            <Label>
                <Label.Text>
                    <Binding Path="Blue"
                             StringFormat="Blue = {0:X2}"
                             Converter="{StaticResource doubleToInt}">
                        <Binding.ConverterParameter>
                            <x:Double>255</x:Double>
                        </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ą double wartość na ConverterParameter właściwość.

Oto wynik:

Selektor kolorów RGB