Search code examples
storyboarduwpdatatemplate

[UWP]The storyboard contained in the DataTemplate is not working properly


Clicking on any item will only work on the storyboard of the first item.

You can download the source from the address below.

http://util.aquerytool.com/Download?fileName=ItemStoryboardApp.zip

Thank you for your reply.

<UserControl
    x:Class="ItemStoryboardApp.View.ItemListMVVMLightView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ItemStoryboardApp.View"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:media="using:Microsoft.Xaml.Interactions.Media"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid x:Name="PART_RootPanel">

        <ItemsControl ItemsSource="{Binding ItemList}" Padding="0,0,0,0">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Foreground="White" Margin="0,0,5,0" Padding="0,0,0,0" Height="40" Command="{Binding DataContext.SelectedItemCommand, ElementName=PART_RootPanel}" CommandParameter="{Binding}" VerticalContentAlignment="Stretch" >
                        <Button.Content>
                            <Grid x:Name="PART_ContinuousDefectPanel" RenderTransformOrigin="0.5, 0.5">
                                <Grid.Resources>
                                    <Storyboard x:Name="SB_ChangedCount">
                                        <DoubleAnimation Storyboard.TargetName="PART_ContinuousDefectPanel" Duration="0:0:0.25" To="1.2" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" AutoReverse="True" />
                                        <DoubleAnimation Storyboard.TargetName="PART_ContinuousDefectPanel" Duration="0:0:0.25" To="1.2" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" AutoReverse="True" />
                                    </Storyboard>
                                </Grid.Resources>

                                <Grid.RenderTransform>
                                    <ScaleTransform x:Name="ImageScale" ScaleX="1" ScaleY="1" />
                                </Grid.RenderTransform>

                                <interactivity:Interaction.Behaviors>
                                    <core:DataTriggerBehavior Binding="{Binding IsSelected}" Value="True"  ComparisonCondition="Equal">
                                        <media:ControlStoryboardAction Storyboard="{StaticResource SB_ChangedCount}" />
                                    </core:DataTriggerBehavior>
                                </interactivity:Interaction.Behaviors>

                                <Rectangle Fill="Orange" RadiusX="10" RadiusY="10"/>
                                <StackPanel Orientation="Horizontal" Margin="10,0,10,0" VerticalAlignment="Center">
                                    <TextBlock Text="{Binding ItemName}" />
                                </StackPanel>

                            </Grid>
                        </Button.Content>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

    </Grid>

</UserControl>



public class ItemListMVVMLightViewModel : ViewModelBase
{
    public ObservableCollection<ItemModel> ItemList
    {
        get { return _itemList; }
        set { _itemList = value; RaisePropertyChanged("ItemList"); }
    }
    ObservableCollection<ItemModel> _itemList = new ObservableCollection<ItemModel>();

    public ICommand SelectedItemCommand { get; private set; }


    public ItemListMVVMLightViewModel()
    {
        InitData();
        InitCommand();
    }

    void InitCommand()
    {
        SelectedItemCommand = new RelayCommand<object>((param) => OnSelectedItemCommand(param));
    }

    void InitData()
    {
        for (int i = 0; i < 10; i++)
        {
            ItemList.Add(new ItemModel() { ItemName = "Name" + i.ToString() });
        }
    }

    void OnSelectedItemCommand(object param)
    {
        if (param == null || (param is ItemModel) == false)
        {
            return;
        }

        foreach (ItemModel i in ItemList)
        {
            i.IsSelected = false;
        }

        ItemModel item = param as ItemModel;
        item.IsSelected = true;
    }



}

Solution

  • According to Storyboard class,

    TargetNameProperty is used to reference another element by its name.For most animation targeting scenarios you won't need to worry about the influence of XAML namescopes, but you might encounter XAML name resolution issues if you're trying to target template parts, or objects that were created using Load(String) and subsequently added to the object tree. For more info, see XAML namescopes.

    Since you're using a storyboard inside a datatemplate, you may encounter XAML name resolution issue. The storyboard always target the first item may lead this issue.

    In your code snippet you are using a DataTrigger for trigger the storyboard. However, it may be a legacy syntax from WPF and early versions of Silverlight prior to VisualStateManager support. I recommend you to storyboard animations for visual states. The following code may achieve the same result as you want you may reference. I think you want to animate one item once it selected. I custom the button style to add your animation to the VisualStateManager.

    <ItemsControl Padding="0,0,0,0" ItemsSource="{Binding ItemList}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button
                        Height="40"
                        Margin="0,0,5,0"
                        Padding="0,0,0,0"
                        VerticalContentAlignment="Stretch"
                        Foreground="White"
                        Command="{Binding DataContext.SelectedItemCommand, ElementName=PART_RootPanel}"
                        CommandParameter="{Binding}">
                        <Button.Style>
                            <Style TargetType="Button">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate TargetType="Button">
                                            <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
                                                <Grid.RenderTransform>
                                                    <ScaleTransform
                                                        x:Name="ImageScale"
                                                        ScaleX="1"
                                                        ScaleY="1" />
                                                </Grid.RenderTransform>
                                                <Rectangle
                                                    Fill="Orange"
                                                    RadiusX="10"
                                                    RadiusY="10" />
                                                <StackPanel
                                                    Margin="10,0,10,0"
                                                    VerticalAlignment="Center"
                                                    Orientation="Horizontal">
                                                    <TextBlock Text="{Binding ItemName}" />
                                                </StackPanel>
                                                <VisualStateManager.VisualStateGroups>
                                                    <VisualStateGroup x:Name="CommonStates">
                                                        <VisualState x:Name="Pressed">
                                                            <Storyboard>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
                                                                </ObjectAnimationUsingKeyFrames>
                                                                <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
                                                                <DoubleAnimation
                                                                    AutoReverse="True"
                                                                    Duration="0:0:0.25"
                                                                    Storyboard.TargetName="RootGrid"
                                                                    Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                                                                    To="1.2" />
                                                                <DoubleAnimation
                                                                    AutoReverse="True"
                                                                    Duration="0:0:0.25"
                                                                    Storyboard.TargetName="RootGrid"
                                                                    Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                                                                    To="1.2" />
                                                            </Storyboard>
                                                        </VisualState>
                                                    </VisualStateGroup>
                                                </VisualStateManager.VisualStateGroups>
                                            </Grid>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </Button.Style>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>