sobota, 15 grudnia 2012

70-511 Rozdział 6 - Binding - konwersje danych

WPF umożliwia łatwą konwersję danych prezentowanych w GUI.

IValueConverter
Interfejs ten implementujemy aby konwertować pojedynczą wartość.
Definicja interfejsu jest następująca:

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

Metody zawarte w tym interfejsie:
  • Convert - konwertuje dane wejściowe do żądanego typu
  • ConvertBack - odwraca konwersję do pierwotnego typu
W większości przypadków konwersja wsteczna nie jest możliwa, z tego względu nie implementuje się metody ConvertBack.Obowiązkowo musimy ją zaimplementować gdy będziemy wykorzystywać bindowanie w obie strony (TwoWay).
Klasa która będzie implementować ten interfejs musi zostać oznaczona atrybutem ValueConversion który mówi z jakiego typu do jakiego następuje konwersja.
Przykład konwertera:

Code:
namespace WpfExample
{
    [ValueConversion(typeof(DateTime), typeof(string))]
    public class DataConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.GlobalizationCultureInfo culture)
        {
            var dateTime = (DateTime?)value;
            if (dateTime.HasValue)
            {
                return dateTime.Value.ToString("dd-MM-yyyy");
            }

            return "";
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.GlobalizationCultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Aby użyć tak napisanego konwertera:
  • w XAML-u definiujemy przestrzeń nazw gdzie znajduje się nasz konwerter
  • tworzymy obiekt naszego konwertera, np w zasobach okna
  • stworzoną instancję przypisujemy do właściwości Converter
Przykład:

Code:
<Window x:Class="WpfExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfExample"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:DataConverter x:Key="DataConverter" />
    </Window.Resources>
    <Grid>
        <TextBlock 
            HorizontalAlignment="Left" VerticalAlignment="Top" 
            Text="{Binding CurrentDateTime, Mode=OneWay, Converter={StaticResource DataConverter}}"/>
    </Grid>
</Window>


Praktyczny przykład konwertera to pobranie z bazy ścieżek do plików graficznych i wyświetlenie ich w aplikacji jako grafiki.
Innym przykładem może być translacja całych napisów. Metody Convert i ConvertBack zawierają referencje do obiektu reprezentującego obecnie wybraną kulturę. Jeżeli aplikacja będzie miała działać w kilku językach w łatwy sposób możemy stworzyć tłumaczenie napisów na odpowiedni język.
Przykład:

Code:
    [ValueConversion(typeof(string), typeof(string))]
    public class LanguageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var textToTranslate = (string) value;
            var translatorService = new TranslatorService();
            switch (culture.ToString())
            {
                case "en-US":
                    return translatorService.PolishToEnglish(textToTranslate);
                case "fr-FR":
                    return translatorService.PolishToFrench(textToTranslate);
                default:
                    return textToTranslate;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var textToTranslate = (string)value;
            var translatorService = new TranslatorService();
            switch (culture.ToString())
            {
                case "en-US":
                    return translatorService.EnglishToPolish(textToTranslate);
                case "fr-FR":
                    return translatorService.FrenchToPolish(textToTranslate);
                default:
                    return textToTranslate;
            }
        }
    }



IMultiValueConverter
Interfejs ten umożliwia tworzenie konwerterów które konwertują wartości z kilku pól w jedną. Przykładem takiej operacji może być obliczanie ceny za kilka sztuk towaru. Mnożymy wtedy dane z pól ilość oraz cena za sztukę.
Interfejs ten posiada tak samo jak IValueConverter dwie metody do konwersji:

Code:
  public interface IMultiValueConverter
  {
    object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
    object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture);
  }

Różnica między tymi dwoma interfejsami jest tak, iż ten drugi przyjmuje w metodzie Convert tablicę obiektów, a w metodzie ConvertBck zwraca tablicę obiektów, a jako parametr przychodzący - tablicę typów.
Przykład:

Code:
namespace WpfExample
{
    public class TotalPriceConverter : IMultiValueConverter
    {

        public object Convert(object[] values, Type targetType, object parameter, System.GlobalizationCultureInfo culture)
        {
            var count = (int)values[0];
            var price = (decimal)values[1];

            return (count * price).ToString("C");
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.GlobalizationCultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

XAML:

Code:
<Window x:Class="WpfExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfExample"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:TotalPriceConverter x:Key="TotalPriceConverter" />
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <TextBlock Text="Amount: "/>
            <TextBlock Text="{Binding Count}"/>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <TextBlock Text="Price: "/>
            <TextBlock Text="{Binding UnitPrice}"/>
        </StackPanel>
        <StackPanel Grid.Row="2" Orientation="Horizontal">
            <TextBlock Text="Amount: "/>
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding Converter="{StaticResource TotalPriceConverter}">
                        <Binding Path="Count" />
                        <Binding Path="UnitPrice" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </StackPanel>
    </Grid>
</Window>

Brak komentarzy:

Prześlij komentarz