dub stylee
dub stylee

Reputation: 3342

Using DataTemplateSelector with ItemContainerStyle

I have a GridView that uses a DataTemplateSelector. It works fine when the DataTemplateSelector is set on the GridView like so:

        <GridView x:Name="PayeesGridView"
                  IsItemClickEnabled="True"
                  ItemTemplateSelector="{StaticResource PayeeTemplateSelector}"
                  ItemsSource="{Binding FilteredPayees,
                                        Mode=OneWay}"
                  Padding="5"
                  SelectionMode="None">

            <interactivity:Interaction.Behaviors>
                <core:EventTriggerBehavior EventName="ItemClick">
                    <core:CallMethodAction MethodName="GridViewItemClick" TargetObject="{Binding Mode=OneWay}" />
                </core:EventTriggerBehavior>
            </interactivity:Interaction.Behaviors>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid x:Name="ItemWrapGrid" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>

            <GridView.ItemContainerStyle>
                <Style TargetType="GridViewItem">
                    <Setter Property="Margin" Value="5" />
                </Style>
            </GridView.ItemContainerStyle>
        </GridView>

However, I am trying to set the DataTemplate inside of the ItemContainerStyle so that I am able to use VisualStateManager. I tried to declare it like this:

        <GridView x:Name="PayeesGridView"
                  IsItemClickEnabled="True"
                  ItemsSource="{Binding FilteredPayees,
                                        Mode=OneWay}"
                  Padding="5"
                  SelectionMode="None">

            <interactivity:Interaction.Behaviors>
                <core:EventTriggerBehavior EventName="ItemClick">
                    <core:CallMethodAction MethodName="GridViewItemClick" TargetObject="{Binding Mode=OneWay}" />
                </core:EventTriggerBehavior>
            </interactivity:Interaction.Behaviors>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid x:Name="ItemWrapGrid" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>

            <GridView.ItemContainerStyle>
                <Style TargetType="GridViewItem">
                    <Setter Property="Margin" Value="5" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="GridViewItem">
                                <Grid>
                                    <Grid.Background>
                                        <SolidColorBrush x:Name="GridBackground" Color="Transparent" />
                                    </Grid.Background>

                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup x:Name="CommonStates">
                                            <VisualState x:Name="Normal" />
                                            <VisualState x:Name="PointerOver">
                                                <VisualState.Setters>
                                                    <Setter Target="GridBackground.Color" Value="Green" />
                                                </VisualState.Setters>
                                                <Storyboard />
                                            </VisualState>
                                            <VisualState x:Name="Pressed">
                                                <VisualState.Setters>
                                                    <Setter Target="GridBackground.Color" Value="#36B536" />
                                                </VisualState.Setters>
                                                <Storyboard />
                                            </VisualState>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>

                                    <ContentPresenter Content="{TemplateBinding Content}"
                                                      ContentTemplate="{TemplateBinding ContentTemplate}"
                                                      ContentTemplateSelector="{StaticResource PayeeTemplateSelector}" />
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GridView.ItemContainerStyle>
        </GridView>

Using a ContentPresenter and specifying the ContentTemplateSelector the same way as the ItemTemplateSelector was on the GridView. Doing it this way, the GridView just displays the object view of each Payee. The VisualStates work properly, but it is not using the DataTemplates that I have defined.

The DataTemplates are defined in the Page.Resources like so:

    <DataTemplate x:Key="OpenPayeeDataTemplate" x:DataType="models:Payee">
        <Grid>
            <Border Width="230"
                    Height="230"
                    Background="White"
                    BorderBrush="#36B536"
                    BorderThickness="4">
                <Grid Margin="5,0,5,0">
                    <Image Width="160"
                           Height="160"
                           Source="{x:Bind LogoBase64, Converter={StaticResource Base64StringToImageSourceConverter}}" />
                    <TextBlock VerticalAlignment="Top"
                               FontSize="14"
                               FontWeight="Bold"
                               Foreground="Black"
                               Text="{x:Bind CompanyName}"
                               TextAlignment="Left"
                               TextWrapping="WrapWholeWords" />
                    <TextBlock VerticalAlignment="Bottom"
                               FontSize="12"
                               FontWeight="Bold"
                               Foreground="Black"
                               Text="{x:Bind AccountNickname}"
                               TextAlignment="Right"
                               TextWrapping="WrapWholeWords" />
                </Grid>
            </Border>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="ClosedPayeeDataTemplate" x:DataType="models:Payee">
        <Grid>
            <Border Width="230"
                    Height="230"
                    Background="White"
                    BorderBrush="#36B536"
                    BorderThickness="4">
                <Grid Margin="5,0,5,0">
                    <Image Width="160"
                           Height="160"
                           Source="{x:Bind LogoBase64, Converter={StaticResource Base64StringToImageSourceConverter}}" />
                    <TextBlock VerticalAlignment="Top"
                               FontSize="14"
                               FontWeight="Bold"
                               Foreground="Black"
                               Text="{x:Bind CompanyName}"
                               TextAlignment="Left"
                               TextWrapping="WrapWholeWords" />
                    <TextBlock VerticalAlignment="Bottom"
                               FontSize="12"
                               FontWeight="Bold"
                               Foreground="Black"
                               Text="{x:Bind AccountNickname}"
                               TextAlignment="Right"
                               TextWrapping="WrapWholeWords" />
                </Grid>
            </Border>
            <Border Width="230"
                    Height="230"
                    Background="Gray"
                    Opacity="0.75" />
        </Grid>
    </DataTemplate>
    <converters:PayeeDataTemplateSelector x:Name="PayeeTemplateSelector"
                                          ClosedPayeeDataTemplate="{StaticResource ClosedPayeeDataTemplate}"
                                          OpenPayeeDataTemplate="{StaticResource OpenPayeeDataTemplate}" />

Alternatively, I have tried to use the VisualStateManager inside the DataTemplates, but they aren't triggered, so I am required to use it outside of the DataTemplate, hence the desire to use the ContentPresenter inside the ItemContainerStyle.

I do something similar with some ListViewItems, but they do not use a DataTemplateSelector so I don't run into the same issue. Is there a way to get VisualStateManager to work from within a DataTemplate, or get the DataTemplateSelector to work from within a ContentPresenter?

EDIT

Here is the XAML I tried putting in Styles/DataTemplates.xaml. The style is being applied, but I do not get any of the VisualStates being triggered.

<DataTemplate x:Key="PaymentTemplate">
    <UserControl>
        <Grid>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal" />
                    <VisualState x:Name="PointerOver">
                        <VisualState.Setters>
                            <Setter Target="GridItemOverlay.Background" Value="Green" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>

            <Border Width="450"
                    Height="Auto"
                    Background="White"
                    BorderBrush="#36B536"
                    BorderThickness="4"
                    CornerRadius="5">

                <Grid Margin="10,5,10,5">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="34" />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Grid.Row="0"
                               Grid.Column="0"
                               Grid.ColumnSpan="2"
                               FontSize="26"
                               FontWeight="Bold"
                               Foreground="Black"
                               Text="{Binding AccountName}"
                               TextAlignment="Left"
                               TextWrapping="WrapWholeWords" />
                    <TextBlock Grid.Row="1"
                               Grid.Column="0"
                               Foreground="Black"
                               Text="{Binding Path=Description}"
                               TextAlignment="Left" />
                    <TextBlock Grid.Row="1"
                               Grid.Column="1"
                               Foreground="Black">
                        <Run Text="Payment Amount: " />
                        <Run Text="{Binding Path=PaymentAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}'}" />
                    </TextBlock>
                    <TextBlock Grid.Row="2"
                               Grid.Column="1"
                               Foreground="Black">
                        <Run Text="Principal Amount: " />
                        <Run Text="{Binding Path=PrincipalAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}'}" />
                    </TextBlock>
                    <TextBlock Grid.Row="3"
                               Grid.Column="0"
                               Foreground="Black">
                        <Run Text="Payment Date: " />
                        <Run Text="{Binding PaymentDate, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:MM/dd/yyyy}'}" />
                    </TextBlock>
                    <TextBlock Grid.Row="3"
                               Grid.Column="1"
                               Foreground="Black">
                        <Run Text="Interest Amount: " />
                        <Run Text="{Binding Path=InterestAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}'}" />
                    </TextBlock>
                </Grid>
            </Border>
            <Border x:Name="GridItemOverlay"
                    Background="Transparent"
                    Opacity="0.50" />
        </Grid>
    </UserControl>
</DataTemplate>

The VisualStates work perfectly fine when set directly using the GridView.ItemContainerStyle to set the Template, but not when trying it from a DataTemplate in a separate resource file. Any ideas?

Upvotes: 1

Views: 522

Answers (2)

dub stylee
dub stylee

Reputation: 3342

I am able to achieve what I am wanting by setting the ContentTemplate on a ContentPresenter inside of my ItemTemplate, like this:

    <GridView.ItemContainerStyle>
        <Style TargetType="GridViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewItem">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal" />
                                    <VisualState x:Name="PointerOver">
                                        <VisualState.Setters>
                                            <Setter Target="GridItemOverlay.Background" Value="Green" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>

                            <ContentPresenter ContentTemplate="{StaticResource PaymentTemplate}" />
                            <Border x:Name="GridItemOverlay"
                                    Background="Transparent"
                                    Opacity="0.50" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </GridView.ItemContainerStyle>

And of course, PaymentTemplate is a DataTemplate defined in DataTemplates.xaml. Ideally, I would like to get the VisualStateManager stuff bundled together with the DataTemplate itself to unclutter the XAML in my View, but this way works for now.

Upvotes: 0

Depechie
Depechie

Reputation: 6142

Not sure on the content template selector. But, your initial thought on using VisualStateManager inside the DataTemplates should work.

There is one thing you missed when trying this out, you need to wrap everything inside the DataTemplate in an UserControl tag! Otherwise the VisualStateManager will not work.

Example found here: https://github.com/AppCreativity/Kliva/blob/master/src/Kliva/XAMLResources/DataTemplates.xaml#L21

Upvotes: 2

Related Questions