<GridView Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Height="600" x:Name="testAdvs" SelectionMode="None" Width="1200" ItemsSource="{Binding Path=Advertisements}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" MaximumRowsOrColumns="4"></VariableSizedWrapGrid>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="200" Tapped="Grid_Tapped_1" Height="200" >
<Image Source="{Binding bigImage}" Name="image" Tapped="Image_Tapped_1">
<Image.Triggers>
<EventTrigger>
<BeginStoryboard><Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="image">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="90"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="180"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="270"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
<Image.Projection>
<PlaneProjection/>
</Image.Projection>
</Image>
<TextBlock Text="{Binding activeName}"></TextBlock>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
主要是在datatemplate 里面的控件使用,EVENTRIGGER
添加数据的动画要简单与删除数据的动画。当控件被加入到程序Visual Tree中,会激发FrameworkElement的Loaded事件(MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.loaded.aspx),此时首先需要在DataTemplate中将Opacity和FontSize属性设置成小值,这样的话,虽然Loaded事件发生时控件已经在Visual Tree里了,但对用户还是不可见的(应为Opacity被设置成0),接着开始Storyboard把不可见的数据项动画显示出来就可以了。
还有一点需要注意,尽管ListBox数据项的Opacity被设置成0,FontSize也被设置成很小的数。但ListBoxItem在被添加的时候还是保持默认高度的,接着很快FontSize被设置,高度才会突然变小,这样动画进行时会是:大-突然小-慢慢变大 这样的过程进行,这点很令人不爽……解决方案是先将DataTemplate中的根节点(本例中的TextBlock)的Visibility设置成Collapsed,这样ListBoxItem在添加时没有占用任何控件。在动画开始的时候,再将Visibility改成Visible,注意此时FontSize已经被应用了,所以ListBoxItem会从小慢慢变大这样按要求进行。
这种方法在前几天提到过(http://www.cnblogs.com/mgen/archive/2011/08/21/2148723.html),这里就不再介绍了。
所以ListBox的DataTemplate是这样的:
<DataTemplate x:Key="dataTemplate">
<TextBlock Name="text"
Text="{Binding}"
Visibility="Collapsed"
Opacity="0"
FontSize="1" />
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="text">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" KeyTime="0:0:0"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
Duration="0:0:0.5"
To="1"/>
<DoubleAnimation Storyboard.TargetProperty="FontSize"
Duration="0:0:0.5"
To="15"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</DataTemplate.Triggers>
</DataTemplate>
由于所以问题都在XAML中解决了,所以添加操作的C#代码只需要将随机数加到数据源中就可以了:
//添加数据
private void Button_Click(object sender, RoutedEventArgs e)
{
int idx = 0;
if (lbx.SelectedIndex != -1)
idx = lbx.SelectedIndex;
list.Insert(idx, r.Next(1000));
}
删除数据的动画要远远复杂与添加数据的动画。这里根本无法利用FrameworkElement的Unloaded事件(MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.unloaded.aspx),从事件名称上就可以看出来Loaded和Unloaded而不是Loading和Unloading!那么事件发生时,控件UI数据是已经显示或者被移除。Loaded事件,我们可以先把Visibility,Opacity和FontSize改成我们需要的值接着利用动画把数据真正显示出来。而Unloaded发生时,数据已经从Visual Tree中移除了,还谈什么动画……
这样的话,我们只能先进行动画,在动画完成后再直接删除数据。因此在删除数据按钮的事件处理方法中,进行如下操作:
步骤3需要在Visual Tree中进行按类型的搜索,用如下方法:
/// <summary>
/// 搜索Visual Tree并尝试返回制定类型的DependencyObject
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public T GetChild<T>(DependencyObject obj) where T : DependencyObject
{
DependencyObject child = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child.GetType() == typeof(T))
break;
else if (child !=null)
{
child = GetChild<T>(child);
if (child != null && child.GetType() == typeof(T))
break;
}
}
return child as T;
}
删除数据方法:
//删除数据
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (lbx.SelectedIndex == -1 || onGoing)
return;
//得到ListBoxItem
var container = lbx.ItemContainerGenerator.ContainerFromIndex(lbx.SelectedIndex);
//得到DataTemplate的TextBlock
var text = GetChild<TextBlock>(container);
//得到Storyboard
var storyboard = this.FindResource("storyboard") asStoryboard;
Storyboard.SetTarget(storyboard, text);
onGoing = true;
remIndex = lbx.SelectedIndex;
//开始动画
storyboard.Begin();
}
Storyboard的定义和添加数据的Storyboard相似,只不过值相反。
最后在Storyboard动画结束后(利用Timeline的Completed事件),再将数据从数据源中删除!OK!
Storyboard的Completed事件代码:
//删除动画结束事件
private void Storyboard_Completed(object sender, EventArgs e)
{
list.RemoveAt(remIndex);
if (list.Count > 0)
{
if (remIndex >= list.Count)
lbx.SelectedIndex = list.Count - 1;
else
lbx.SelectedIndex = remIndex;
}
onGoing = false;
} 作者:Mgen(刘圆圆)