sobota, 22 grudnia 2012

70-511 Rozdział 7 - Binding - Data Templates

Data Templates - czyli szablon prezentacji danych określa w jaki sposób użytkownik zobaczy dane prezentowane np. w ListBox-ie.
Do tej pory wykorzystywaliśmy dla ListBoxa właściwość DisplayMemberPath. Teraz możemy napisać szablon:

Code:
        <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Title}"></TextBlock>
                            <TextBlock Text=" - "></TextBlock>
                            <TextBlock Text="{Binding Author}"></TextBlock>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

Efekt:


W zależności od tego czy mamy do czynienia z kontrolką typu Item (np. ListBox) czy też Content (Label) przypisujemy nasz szablon do odpowiedniej właściwości:
  • Items control - ItemTemplate
  • Content control - ContentTemplate
 Większość szablonów definiujemy jako zasoby, które następnie przypisujemy do odpowiedniej kontrolki:

Code:
<Window x:Class="Binding_DataTemplates.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="BookTemplate">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Title}"></TextBlock>
                    <TextBlock Text=" - "></TextBlock>
                    <TextBlock Text="{Binding Author}"></TextBlock>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource BookTemplate}">
            <!--
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Title}"></TextBlock>
                            <TextBlock Text=" - "></TextBlock>
                            <TextBlock Text="{Binding Author}"></TextBlock>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
            -->
        </ListBox>
    </Grid>
</Window>




Konwertery
Konwertery świetnie nadają się do warunkowego formatowania danych, np. zmiana koloru tekstu w TextBlock jeżeli cena książki jest wyższa od 10 złotych:

Code:
    [ValueConversion(typeof(decimal), typeof(Brush))]
    public class PriceForegroundConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var price = (decimal) value;
            if (price > 10)
            {
                return Brushes.Red;
            }

            return Brushes.Black;
        }

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

Code:
    <Window.Resources>
        <local:PriceForegroundConverter x:Key="ForegroudPriceConverter" />
        <DataTemplate x:Key="BookTemplate">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Title}" Foreground="{Binding Price, Converter={StaticResource ForegroudPriceConverter}}"></TextBlock>
                    <TextBlock Text=" - "></TextBlock>
                    <TextBlock Text="{Binding Author}"></TextBlock>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>




DataTemplateSelector
Pozwala przypisać szablon wyświetlania danych w zależności od bindowanych danych. Dla przykładu możemy zrealizować poniższy scenariusz:
Jeżeli cena książki jest wyższa od 5 zł, chcemy wyświetlić jej tytuł na czerwono, oraz po autorze dodać informację o cenie - także wyświetloną na czerwono. W tym celu najpierw tworzymy dwa szablony wyświetlania danych:

Code:
    <Window.Resources>
        <local:PriceForegroundConverter x:Key="ForegroudPriceConverter" />
        <local:PriceDataTemplateSelector x:Key="PriceDataTemplateSelector" />
        <DataTemplate x:Key="BookTemplate">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Title}" />
                    <TextBlock Text=" - " />
                    <TextBlock Text="{Binding Author}" />
                </StackPanel>
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="BookTemplateAlternative">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Title}" Foreground="Red" />
                    <TextBlock Text=" - " />
                    <TextBlock Text="{Binding Author}" />
                    <TextBlock Text=" - "></TextBlock>
                    <TextBlock Text="{Binding Price}" Foreground="Red" />
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>

Następnym krokiem jest implementacja klasy PriceDataTemplateSelector, która będzie dziedziczyć po klasie DataTemplateSelector. Klasa DataTemplateSelector zawiera jedną metodę, która możemy nadpisać - SelectTemplate. Metoda ta ma na celu zwrócić odpowiedni szablon. Przyjmuje ona dwa parametry:
  • item - czyli bindowany obiekt
  • container - kontener, do którego jest bindowany obiekt
Przykładowa implementacja:

Code:
    public class PriceDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var element = container as FrameworkElement;
            var book = item as Book;
            if (element != null && item != null && book != null)
            {
                if (book.Price > 5)
                {
                    return (DataTemplate)element.FindResource("BookTemplateAlternative");
                }
                else
                {
                    return (DataTemplate)element.FindResource("BookTemplate");
                }
            }

            return null;
        }
    }


Ostatnim elementem do wykonania jest przypisanie do kontrolki naszego selektora:
Tworzymy zasób związany z selektorem:

Code:
        <local:PriceDataTemplateSelector x:Key="PriceDataTemplateSelector" />

oraz przypisujemy go do kontrolki:

Code:
        <ListBox ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource PriceDataTemplateSelector}">


Efekt:



Źródła przykładów realizowanych w tym poście (wraz z przykładowymi danymi) - do pobrania z linku: http://sdrv.ms/12js6rd

Brak komentarzy:

Prześlij komentarz