怎么给listbox 的item 添加动画1?

<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中移除了,还谈什么动画……

 

这样的话,我们只能先进行动画,在动画完成后再直接删除数据。因此在删除数据按钮的事件处理方法中,进行如下操作:

  1. 得到ListBox选择的索引值
  2. 利用ItemsControl的ItemContainerGenerator从索引值得到所谓的数据容器(ListBoxItem)
  3. 从ListBoxItem中找到DataTemplate需要进行动画的TextBlock
  4. 从资源中找到定义好的Storyboard并设置好相应的动画参数
  5. 开始动画

 

步骤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(刘圆圆)

posted on 2012-09-14 11:20  GIS-MAN  阅读(498)  评论(0编辑  收藏  举报

导航