为什么这个列表框项目不会动画?

时间:2014-02-17 10:05:23

标签: c# xaml windows-phone-8 storyboard silverlight-5.0

我正在尝试重新创建Windows Phone连续体转换(一个选定的项目圈出来并进入视图,例如在邮件客户端中打开电子邮件时),我似乎无法让一个动画工作

当您返回项目列表时,之前选择的项目必须从左上角的某处滑回到列表中。我想我会保留对所选项的引用,然后在页面的Loaded事件处理程序中,检查该引用是否为null,如果是,则创建一个storyboard,找到正确的列表框项,将其设置为动画的目标,并运行它。

但是,这不起作用。这是listbox itemtemplate:

<StackPanel x:Name="commuteStackPanel" local:TiltEffect.IsTiltEnabled="True" Margin="0,0,0,38" Tap="StackPanel_Tap">
    <TextBlock Style="{StaticResource PhoneTextTitle3Style}" TextTrimming="WordEllipsis" Text="{Binding Title}" />
    <TextBlock Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding SelectedDays}" Margin="12,0,12,0"/>                                
</StackPanel>

这是动画,定义为页面资源:

<Storyboard xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x:Key="continuumStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" >
    <EasingDoubleKeyFrame KeyTime="0" Value="-70"/>
    <EasingDoubleKeyFrame KeyTime="0:0:4.15" Value="0">
        <EasingDoubleKeyFrame.EasingFunction>
            <ExponentialEase EasingMode="EaseOut" Exponent="3"/>
        </EasingDoubleKeyFrame.EasingFunction>
    </EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" >
    <EasingDoubleKeyFrame KeyTime="0" Value="-30"/>
    <EasingDoubleKeyFrame KeyTime="0:0:4.15" Value="0">
        <EasingDoubleKeyFrame.EasingFunction>
            <ExponentialEase EasingMode="EaseOut" Exponent="3"/>
        </EasingDoubleKeyFrame.EasingFunction>
    </EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

这是页面的代码隐藏:

    private FrameworkElement lastSelectedElement = null;

    private void StackPanel_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        this.lastSelectedElement = sender as FrameworkElement;
    }

    private void page_Loaded(object sender, RoutedEventArgs e)
    {            
        if (this.lastSelectedElement != null)
        {
            // Using the last selected element's datacontext, find the relevant ListBoxItem
            var listBoxItem = commutesListBox.ItemContainerGenerator.ContainerFromItem(this.lastSelectedElement.DataContext);

            // Get the actual stackpanel we want to animate
            var element = FindVisualChild<StackPanel>(listBoxItem);

            // Ensure it has the proper transforms
            element.RenderTransform = new CompositeTransform { TranslateX = 0, TranslateY = 0 };

            // Get the storyboard and make sure it is not playing.
            var storyboard = Resources["continuumStoryboard"] as Storyboard;
            storyboard.Stop();

            // Set the stackpanel as the target for each timeline in the storyboard
            foreach (var timeline in storyboard.Children)
            {
                Storyboard.SetTarget(timeline, element);
            }

            // Play the animation.
            storyboard.Begin();
        }
    }

我从MSDN文章中复制的FindVisualChild方法:

private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if (child != null && child is childItem)
                return (childItem)child;
            else
            {
                childItem childOfChild = FindVisualChild<childItem>(child);
                if (childOfChild != null)
                    return childOfChild;
            }
        }
        return null;
    }

然而,这不起作用。如果我设置任何其他元素,例如列表框本身,作为动画的目标,我可以看到它正在播放,但是当我设置datatemplate中的任何元素时,没有任何反应。没有错误,没有。

我想我会尝试并尝试通过替换

来动画列表框的第一项
this.lastSelectedElement.DataContext

commutesListBox.Items.First()

但仍然没有骰子。我在这里缺少什么?

编辑我已经设法让动画运行,但我仍然不明白为什么。事实证明,在Loaded事件中,viewmodel将重新填充列表框绑定的ObservableCollection。在阻止这种情况发生之后,动画就会播放。

我没有得到的是,即使您没有对绑定值或datacontext执行任何操作,问题仍然存在,而是使用Items.First()。即使viewmodel发生了变化,它仍然应该有一个First()项目(并逐步显示它确实存在)。

1 个答案:

答案 0 :(得分:1)

嗯,我用你的代码构建了一个简单的应用程序(你可以downlad it here),所有东西都应该按照我的想法进行(我认为)。在我的应用程序中:

  • 使用第一个按钮添加一些项目
  • 点击一个项目,
  • 点击第二个按钮进行动画制作。

可能问题在于您的page_Loaded事件被触发的时间 - 您必须先在代码中点按StackPanel,当Page加载时,用户没有机会点击项目。