Xamarin.Forms Převaděče hodnot vazeb

Datové vazby obvykle přenášejí data ze zdrojové vlastnosti do cílové vlastnosti a v některých případech z cílové vlastnosti do zdrojové vlastnosti. Tento přenos je jednoduchý, pokud jsou vlastnosti zdroje a cíle stejného typu nebo pokud lze jeden typ převést na druhý typ prostřednictvím implicitního převodu. Pokud tomu tak není, musí proběhnout převod typu.

V článku Formátování řetězců jste viděli, jak můžete použít StringFormat vlastnost datové vazby k převodu libovolného typu na řetězec. Pro jiné typy převodů je nutné napsat nějaký specializovaný kód ve třídě, která implementuje IValueConverter rozhraní. (Univerzální platforma Windows obsahuje podobnou třídu pojmenovanou IValueConverter v Windows.UI.Xaml.Data oboru názvů, ale to IValueConverter je v Xamarin.Forms oboru názvů.) Třídy, které implementujíIValueConverter, se nazývají převaděče hodnot, ale také se často označují jako převaděče vazeb nebo převaděče hodnot vazby.

IValueConverter – rozhraní

Předpokládejme, že chcete definovat datovou vazbu, kde je zdrojová vlastnost typuint, ale cílová vlastnost je .bool Chcete, aby tato datová vazba generuje false hodnotu, pokud je celočíselná zdroj rovna 0, a true jinak.

Můžete to provést pomocí třídy, která implementuje IValueConverter rozhraní:

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

Instanci této třídy nastavíte na Converter vlastnost Binding třídy nebo na Converter vlastnost Binding rozšíření značek. Tato třída se stane součástí datové vazby.

Metoda Convert se volá při přesunu dat ze zdroje do cíle v OneWay vazbách nebo TwoWay vazbách. Parametr value je objekt nebo hodnota ze zdroje datové vazby. Metoda musí vrátit hodnotu typu cíle datové vazby. Zde zobrazená metoda přetypuje value parametr na hodnotu int a pak ji porovná s hodnotou 0 pro návratovou bool hodnotu.

Metoda ConvertBack se volá, když se data přesunou z cíle do zdroje nebo TwoWayOneWayToSource vazby. ConvertBack provádí opačný převod: Předpokládá, že value parametr je bool z cíle, a převede ho na návratovou int hodnotu pro zdroj.

Pokud datová vazba obsahuje StringFormat také nastavení, převaděč hodnot se vyvolá před formátováním výsledku jako řetězec.

Stránka Povolit tlačítka v ukázce ukazuje, jak použít tento převaděč hodnot v datové vazbě. Vytvoří IntToBoolConverter instanci ve slovníku prostředků stránky. Pak se odkazuje s rozšířením StaticResource značek k nastavení Converter vlastnosti ve dvou datových vazbách. Je velmi běžné sdílet převaděče dat mezi několika datovými vazbami na stránce:

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

Pokud se převaděč hodnot používá na více stránkách vaší aplikace, můžete ho vytvořit ve slovníku prostředků v souboru App.xaml .

Stránka Povolit tlačítka ukazuje běžnou potřebu při Button provádění operace na základě textu, který uživatel zadá do Entry zobrazení. Pokud do souboru Entrynení zadáno nic, Button mělo by být zakázáno. Každá Button obsahuje datovou vazbu pro svou IsEnabled vlastnost. Zdroj vazby dat je Length vlastnost Text vlastnosti odpovídající Entry. Pokud tato Length vlastnost není 0, vrátí true převaděč hodnot a Button je povolen:

Povolit tlačítka

Všimněte si, že Text vlastnost v každé Entry z nich je inicializována na prázdný řetězec. Vlastnost Text je null ve výchozím nastavení a datová vazba v takovém případě nebude fungovat.

Některé převaděče hodnot jsou napsány speciálně pro konkrétní aplikace, zatímco jiné jsou generalizovány. Pokud víte, že převaděč hodnot bude použit pouze ve OneWay vazbách, pak ConvertBack metoda může jednoduše vrátit null.

Výše Convert uvedená metoda implicitně předpokládá, že value argument je typu int a návratová hodnota musí být typu bool. Podobně metoda předpokládá, ConvertBack že value argument je typu bool a návratová hodnota je int. Pokud tomu tak není, dojde k výjimce za běhu.

Převaděče hodnot můžete napsat tak, aby byly obecnější a přijímaly několik různých typů dat. Tyto Convert metody ConvertBack mohou použít as nebo is operátory s parametrem value , nebo můžou tento parametr volat GetType , aby určil jeho typ, a pak provést něco vhodného. Očekávaný typ návratové hodnoty každé metody je dán parametrem targetType . Někdy se převaděče hodnot používají s datovými vazbami různých cílových typů; Převaděč hodnot může použít targetType argument k provedení převodu pro správný typ.

Pokud se převod provedený pro různé jazykové verze liší, použijte culture pro tento účel parametr. ConvertConvertBack Argument a parameter je popsán dále v tomto článku.

Vlastnosti převaděče vazeb

Třídy převaděče hodnot mohou mít vlastnosti a obecné parametry. Tento konkrétní převaděč hodnot převede bool zdroj na objekt typu T cíle:

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

Stránka Přepnout indikátory ukazuje, jak se dá použít k zobrazení hodnoty Switch zobrazení. I když je běžné vytvořit instanci převaděčů hodnot jako prostředky ve slovníku prostředků, tato stránka ukazuje alternativu: Každý převaděč hodnot je vytvořena instance mezi Binding.Converter značkami elementů vlastností. Označuje x:TypeArguments obecný argument a TrueObjectFalseObject oba jsou nastaveny na objekty tohoto 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>

V poslední ze tří Switch a Label párů je obecný argument nastaven na Style, a celé Style objekty jsou k dispozici pro hodnoty TrueObject a FalseObject. Tyto přepisují implicitní styl pro Label sadu ve slovníku prostředků, takže vlastnosti v daném stylu jsou explicitně přiřazeny Label. Přepnutí Switch příčin odpovídajících Label změnám:

Indikátory přepínače

Je také možné použít Triggers k implementaci podobných změn v uživatelském rozhraní na základě jiných zobrazení.

Parametry převaděče vazeb

Třída Binding definuje ConverterParameter vlastnost a Binding rozšíření značek také definuje ConverterParameter vlastnost. Pokud je tato vlastnost nastavena, je hodnota předána Convert do a ConvertBack metody jako parameter argument. I když je instance převaděče hodnot sdílena mezi několika datovými vazbami, ConverterParameter může se lišit, aby prováděl poněkud odlišné převody.

Použití ConverterParameter je demonstrováno pomocí programu pro výběr barev. V tomto případě RgbColorViewModel má tři vlastnosti typu double s názvem Red, Greena Blue že používá k vytvoření Color hodnoty:

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

Rozsah Red, Greena Blue vlastnosti v rozmezí od 0 do 1. Můžete ale chtít, aby se komponenty zobrazovaly jako dvouciferné šestnáctkové hodnoty.

Chcete-li tyto hodnoty zobrazit jako šestnáctkové hodnoty v jazyce XAML, musí být vynásobeny hodnotou 255, převedeny na celé číslo a poté formátovány se specifikací "X2" ve StringFormat vlastnosti. První dva úkoly (vynásobené číslem 255 a převodem na celé číslo) je možné zpracovat převaděčem hodnot. Aby byl převaděč hodnot co nejobecně zobecněn, lze faktor násobení zadat pomocí ConverterParameter vlastnosti, což znamená, že jako argument zadává Convert a ConvertBack metody parameter :

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

Převede Convert z argumentu na doubleint hodnotu a vynásobí hodnotou; ConvertBack celočíselnou parameter hodnotu parameter vydělí value a vrátí double výsledek. (V níže uvedeném programu se převaděč hodnot používá pouze v souvislosti s formátováním řetězců, takže ConvertBack se nepoužívá.)

Typ argumentu parameter se bude pravděpodobně lišit v závislosti na tom, jestli je datová vazba definovaná v kódu nebo XAML. ConverterParameter Pokud je vlastnost Binding nastavena v kódu, bude pravděpodobně nastavena na číselnou hodnotu:

binding.ConverterParameter = 255;

Vlastnost ConverterParameter je typu Object, takže kompilátor jazyka C# interpretuje literál 255 jako celé číslo a nastaví vlastnost na tuto hodnotu.

V jazyce XAML se ale ConverterParameter pravděpodobně nastaví takto:

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

255 vypadá jako číslo, ale protože ConverterParameter je typu Object, analyzátor XAML považuje 255 za řetězec.

Z tohoto důvodu převaděč hodnot uvedený výše obsahuje samostatnou GetParameter metodu, která zpracovává případy parameter typu double, intnebo string.

Stránka selektoru barev RGB vytvoří DoubleToIntConverter instanci ve slovníku prostředků podle definice dvou implicitních stylů:

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

Hodnoty Red a Green vlastnosti jsou zobrazeny s rozšířením Binding značek. Vlastnost Blue však vytvoří instanci Binding třídy, aby ukázala, jak lze explicitní double hodnotu nastavit na ConverterParameter vlastnost.

Tady je výsledek:

Výběr barvy RGB