问题
My requirement: when tapped on the border in ListViewItem(DataTemplate) an overlay should appear on top of it with animation.
In my listview data template I defined a visual state at the root. I want to goto the visual state when user taps on the border. I have tried following xaml but it is not working
<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>
回答1:
This question is more complex than I initially thought.
First, let's correct a few issues in your xaml code.
- The following line needs to be removed. It's like saying 'go find a state named
OverlayState
on thecheckedBorder
element'. Clearly that state is not on that element. Also, changing theElementName
binding to point to the top levelGrid
(where the visual state group is) won't work either, I will explain why later.
TargetObject="{Binding ElementName=checkedBorder}"
- You should always give your
VisualStateGroup
a name, like this -
<VisualStateGroup x:Name="MyStates">
- You need to set
IsHitTestVisible
toFalse
on your overlayBorder
, otherwise theBorder
with image background will not be able to receive theTapped
event because it's sitting behind the overlay one.
I thought it should be good to go. However, if you run the app now, you will get an unhandled exception saying
Target does not define any VisualStateGroups.
If you add back the TargetObject
ElementName
binding and change it to point to the top level Grid
, the exception will go away but the visual state is not called.
TargetObject="{Binding ElementName=myFirstLevelGridWhereTheVSGroupIs}"
This is because a normal VisualStateManager
only works for Control
s not FrameworkElement
s since your Grid
is not a type of Control
.
In a WP Silverlight app, it's fairly simple to fix. All you need to do is to add a built-in CustomVisualStateManager
which allows you to pass in a FrameworkElement
on top of the VisualStateGroups
definition. But such class doesn't exist in WinRT.
I asked a question about this a while ago and eventually came up with an answer.
Include this class into your project, and add the reference in your xaml code, just before your VisualStateGroups
definition.
<VisualStateManager.CustomVisualStateManager>
<local:ExtendedVisualStateManager />
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MyStates">
<VisualState x:Name="OverlayState">
Lastly, because unlike the GoToStateAction
in Silverlight app, the WinRT's GoToStateAction
doesn't handle CustomVisualStateManager
, you will have to create a custom GoToStateAction
too.
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);
}
}
And replace the built-in one with this.
<i:Interaction.Behaviors>
<iCore:EventTriggerBehavior EventName="Tapped">
<local:ExtendedGoToStateAction StateName="OverlayState"/>
</Core:EventTriggerBehavior>
You should be able to see the animation working now. :)
来源:https://stackoverflow.com/questions/27899755/goto-visualstate-in-listivew-item-datetemplate-windows-phone-8-1