I'm attempting to bring a templated item forward (ZIndex) in a databound stackpanel. Since a stackpanel creates a ContentPresenter for each item within it, my visual tree looks like this:
ItemsControl
Border
ItemsPresenter
StackPanel
ContentPresenter
ToggleButton
ContentPresenter
ToggleButton
ContentPresenter
ToggleButton
When a ToggleButton is clicked, it fires off a storyboard like this:
<Storyboard x:Key="MyStoryboard" >
<Int32AnimationUsingKeyFrames BeginTime="0:0:0.000" Duration="0:0:0.350"
Storyboard.TargetProperty="TemplatedParent.(Panel.ZIndex)" >
<Int32KeyFrameCollection>
<DiscreteInt32KeyFrame KeyTime="0:0:0.000" Value="99" />
</Int32KeyFrameCollection>
</Int32AnimationUsingKeyFrames>
</Storyboard>
<Style x:Key="SubStateOptionButtonStyle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<!-- Toggle Button Contents here -->
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MyStoryboard}" />
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
However, the TemplatedParent.(Panel.ZIndex) gives me a strange exception:
Value cannot be null. Parameter name: dp
at System.Windows.DependencyObject.GetValue(DependencyProperty dp) at System.Windows.Media.Animation.Storyboard.ProcessComplexPath(HybridDictionary clockM开发者_运维问答appings, DependencyObject targetObject, PropertyPath path, AnimationClock animationClock, HandoffBehavior handoffBehavior, Int64 layer) at System.Windows.Media.Animation.Storyboard.ClockTreeWalkRecursive(Clock currentClock, DependencyObject containingObject, INameScope nameScope, DependencyObject parentObject, String parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, HybridDictionary clockMappings, Int64 layer) at System.Windows.Media.Animation.Storyboard.ClockTreeWalkRecursive(Clock currentClock, DependencyObject containingObject, INameScope nameScope, DependencyObject parentObject, String parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, HybridDictionary clockMappings, Int64 layer) at System.Windows.Media.Animation.Storyboard.BeginCommon(DependencyObject containingObject, INameScope nameScope, HandoffBehavior handoffBehavior, Boolean isControllable, Int64 layer) at System.Windows.Media.Animation.BeginStoryboard.Begin(DependencyObject targetObject, INameScope nameScope, Int64 layer)
etc.
I've double checked via code-behind that the ToggleButton's TemplatedParent is indeed the ContentPresenter and I can set the ZIndex with something like this:
Panel.SetZIndex((sender as ToggleButton).TemplatedParent as UIElement, 99);
But I'd like to animate it with a storyboard, preferably with straight XAML, since it needs to stay forward for the duration of the storyboard, then go back to where it was.
I've considered inheriting from ItemsControl to prevent the ContentPresenter from being created but that's a heavy-handed solution to something that seems like it should be easy.
Here is the answer to this question: http://social.msdn.microsoft.com/Forums/en/wpf/thread/7b9b8209-063d-46b2-a03f-98b393cf9514 (by Min Zhu [MSFT])
Your original code doesn't work because TemplatedParent is not a dependency property. So it is not a valid path for animation.
The code TI82 suggests is correct. It still doesn't work because the TemplatedParent is the Button. But the element you want to animate is the item container.
To animate the item container, you can use ItemsControl's ItemContainerStyle. Button.Click is a bubbling routed event, so it will bubble from the button to the item container as well.
Try the following code.
<Window.Resources>
<Storyboard x:Key="MyStoryboard">
<ColorAnimation Storyboard.TargetName="ButtonRect"
Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
To="Red"
Duration="0:0:0.350"
FillBehavior="Stop"/>
</Storyboard>
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Panel.ZIndex" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentPresenter}, Mode=OneWayToSource, Path=(Panel.ZIndex)}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Height="60" Margin="0,0,0,-10" >
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="15">
<Rectangle x:Name="ButtonRect" RadiusX="15" RadiusY="15" Fill="AliceBlue" />
</Border>
<TextBlock Text="{Binding}" FontSize="15" TextAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MyStoryboard}" />
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="MyButtonTemplate">
<Grid>
<Button Style="{StaticResource MyButtonStyle}" />
</Grid>
</DataTemplate>
<Storyboard x:Key="MyStoryboard2">
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.ZIndex)"
BeginTime="0:0:0.000" Duration="0:0:0.350" FillBehavior="Stop">
<Int32KeyFrameCollection>
<DiscreteInt32KeyFrame KeyTime="0:0:0.000" Value="99" />
</Int32KeyFrameCollection>
</Int32AnimationUsingKeyFrames>
</Storyboard>
<Style x:Key="MyItemContainerStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard Storyboard="{StaticResource MyStoryboard2}"/>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="ABCDEF"
ItemTemplate="{StaticResource MyButtonTemplate}"
ItemContainerStyle="{StaticResource MyItemContainerStyle}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
精彩评论