我的要求:在ListViewItem(DataTemplate)中点击边框时,应该在其顶部出现一个带有动画的叠加层。
在我的列表视图数据模板中,我在根目录定义了视觉状态。我想在用户点击边框时进入视觉状态。我试过遵循 xaml,但它不起作用
<DataTemplate x:Key="MyTemplate">
<Grid Background="{Binding ItemBackground}"
Margin="0,0,0,5" Height="auto">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup >
<VisualState x:Name="OverlayState">
<Storyboard >
<DoubleAnimation Storyboard.TargetName="checkedBorder"
Storyboard.TargetProperty="Opacity"
Duration="0"
To="1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Height="auto" Margin="14,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="55"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<!--Image Section" -->
<Grid Height="108" Margin="0,8,0,0" VerticalAlignment="Top">
<Grid Margin="0">
<Border HorizontalAlignment="Left" Margin="0" VerticalAlignment="Bottom" Width="98" Height="98" CacheMode="BitmapCache" CornerRadius="30">
<Border.Background>
<ImageBrush ImageSource="{Binding ImageSource}" Stretch="Fill"></ImageBrush>
</Border.Background>
<i:Interaction.Behaviors>
<icore:EventTriggerBehavior EventName="Tapped">
<icore:GoToStateAction StateName="OverlayState" TargetObject="{Binding ElementName=checkedBorder}"></icore:GoToStateAction>
</icore:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Border>
<!-- Overlay Border -->
<Border HorizontalAlignment="Left" Opacity="0" x:Name="checkedBorder" Margin="0" Background="#99000000" VerticalAlignment="Bottom"
Width="98" Height="98" CacheMode="BitmapCache" CornerRadius="30">
</Border>
</Grid>
</Grid>
</Grid>
</Grid>
</DataTemplate>
这个问题比我最初想象的要复杂。
首先,让我们更正 xaml 代码中的一些问题。
- 需要删除以下行。这就像说"在
checkedBorder
元素上找到一个名为OverlayState
的状态"。显然,该状态不在该元素上。此外,将ElementName
绑定更改为指向顶级Grid
(视觉状态组所在的位置)也不起作用,稍后我将解释原因。
TargetObject="{Binding ElementName=checkedBorder}"
- 你应该总是给你的
VisualStateGroup
起一个名字,就像这样——
<VisualStateGroup x:Name="MyStates">
- 您需要将
IsHitTestVisible
设置为在叠加Border
上False
,否则具有图像背景的Border
将无法接收Tapped
事件,因为它位于叠加事件后面。
我想应该很好。但是,如果您现在运行该应用程序,您将收到一个未处理的异常,指出
Target 未定义任何 VisualStateGroups。
如果重新添加TargetObject
ElementName
绑定并将其更改为指向顶级Grid
,则异常将消失,但不调用视觉状态。
TargetObject="{Binding ElementName=myFirstLevelGridWhereTheVSGroupIs}"
这是因为正常的VisualStateManager
仅适用于Control
而不是FrameworkElement
,因为您的Grid
不是一种Control
。
在WP Silverlight应用程序中,修复起来相当简单。您需要做的就是添加一个内置CustomVisualStateManager
,它允许您在VisualStateGroups
定义之上传入FrameworkElement
。但此类在 WinRT 中不存在。
不久前我问了一个关于这个问题的问题,最终得出了答案。
将此类包含在项目中,并在 xaml 代码中添加引用,紧接在VisualStateGroups
定义之前。
<VisualStateManager.CustomVisualStateManager>
<local:ExtendedVisualStateManager />
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MyStates">
<VisualState x:Name="OverlayState">
最后,由于与 Silverlight 应用程序中的GoToStateAction
不同,WinRT 的GoToStateAction
不处理CustomVisualStateManager
,您还必须创建自定义GoToStateAction
。
public class ExtendedGoToStateAction : DependencyObject, IAction
{
public string StateName
{
get { return (string)GetValue(StateNameProperty); }
set { SetValue(StateNameProperty, value); }
}
public static readonly DependencyProperty StateNameProperty =
DependencyProperty.Register("StateName", typeof(string), typeof(ExtendedGoToStateAction), new PropertyMetadata(string.Empty));
public bool UseTransitions
{
get { return (bool)GetValue(UseTransitionsProperty); }
set { SetValue(UseTransitionsProperty, value); }
}
public static readonly DependencyProperty UseTransitionsProperty =
DependencyProperty.Register("UseTransitions", typeof(bool), typeof(ExtendedGoToStateAction), new PropertyMetadata(false));
public object Execute(object sender, object parameter)
{
return ExtendedVisualStateManager.GoToElementState((FrameworkElement)sender, this.StateName, this.UseTransitions);
}
}
并用这个替换内置的。
<i:Interaction.Behaviors>
<iCore:EventTriggerBehavior EventName="Tapped">
<local:ExtendedGoToStateAction StateName="OverlayState"/>
</Core:EventTriggerBehavior>
您应该能够看到动画现在正在工作。 :)