访问 Visualstate 动画的 ContentPresenter 子级

Access ContentPresenter children for Visualstate animation

我正在使用以下 GridView 并且有一个 ItemTemplate 里面有 3 个元素。

现在我想做的是在 GridViewItem 上为 PointerOver 上的 MyTextBlock 不透明度设置动画。

<GridView x:Name="MyList" ItemContainerStyle="{StaticResource GridViewItemContainerStyle}" ItemsSource="{Binding MyList}">
<GridView.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="200" />
                <RowDefinition Height="3" />
                <RowDefinition Height="80" />
            </Grid.RowDefinitions>
            <Image Grid.Row="0" Source="{Binding Url}" />
            <ProgressBar Grid.Row="1" IsIndeterminate="True" />
            <TextBlock Name="MyTextBlock" Opacity="0" Text="Test" />
        </Grid>
    </DataTemplate>
</GridView.ItemTemplate>
</GridView>

ItemContainerStyle是这样的。问题是,我无法从这里使用 Storyboard.TargetName="MyTextBlock" 访问 MyTextBlock,因为它在 ContentPresenter 中。 我怎样才能在 ContentPresenter?

中制作一个元素的视觉状态动画
<Style TargetType="GridViewItem" x:Key="GridViewItemContainerStyle">
       ...
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="GridViewItem">
                    <Grid x:Name="ContentBorder" Control.IsTemplateFocusTarget="True" RenderTransformOrigin="0.5,0.5">                          
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="BorderRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="1" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Rectangle x:Name="BorderRectangle" Fill="{ThemeResource SystemControlHighlightListAccentLowBrush}" Opacity="0" />
                        <ContentPresenter x:Name="ContentPresenter" ContentTransitions="{TemplateBinding ContentTransitions}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

编辑: 我尝试使用以下 TargetProperty,但它只是设置整个 ContentPresenter 的不透明度 而不仅仅是 TextBlock 在里面。

<DoubleAnimation Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Opacity)" Duration="0" To="1" />

Problem is, i can't access MyTextBlock with Storyboard.TargetName="MyTextBlock" from here since it's inside the ContentPresenter. How can i do a visualstate animation of an element inside the ContentPresenter?

你可以在DataTemplate中添加两个visualstates(PointerEnteredPointerExited):

<GridView x:Name="MyList" Grid.Row="1" ItemContainerStyle="{StaticResource GridViewItemContainerStyle}" >
        <GridView.ItemTemplate>
            <DataTemplate>
                <Grid PointerExited="Grid_PointerExited" PointerEntered="Grid_PointerEntered">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup>
                            <VisualState x:Name="PointerEntered">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="MyTextBlock" Storyboard.TargetProperty="Opacity" Duration="0" To="1" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="PointerExited">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="MyTextBlock" Storyboard.TargetProperty="Opacity" Duration="0" To="0" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="200" />
                        <RowDefinition Height="3" />
                        <RowDefinition Height="80" />
                    </Grid.RowDefinitions>
                    <Image Grid.Row="0" Source="{Binding Url}" />
                    <ProgressBar Grid.Row="1" IsIndeterminate="True" />
                    <TextBlock Grid.Row="2" Name="MyTextBlock" Opacity="0" Text="Test" />
                </Grid>
            </DataTemplate>
        </GridView.ItemTemplate>
</GridView>

并在 Grid.PointerEnteredGrid.PointerExited 事件中使用以下代码来启动 storyboard

private void Grid_PointerExited(object sender, PointerRoutedEventArgs e)
{
    Grid grid = sender as Grid;
    var visualStateGroups = VisualStateManager.GetVisualStateGroups(grid);
    var visualStateGroup = visualStateGroups[0];
    visualStateGroup.States[1].Storyboard.Begin();
}

private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    Grid grid = sender as Grid;
    var visualStateGroups = VisualStateManager.GetVisualStateGroups(grid);
    var visualStateGroup = visualStateGroups[0];
    visualStateGroup.States[0].Storyboard.Begin();
}

DataTemplate 可以来自任何地方(应用程序资源、Window 资源、本地资源、代码),因此它使用自己的 NameScope

由于 Namescope 个问题,您无法使用 MyTextBlock。因此,最好将 VisualStates 定义为 DataTemplate 本身的一部分。