I ran into a problem. I'm trying to animate a simple Path with PointAnimation. I have a working solution for WPF, and I tried to use it in my Metro app. However it's syntactically correct, it doesn't do anything. What I missed? What I need to change in my XAML?
<Path Stroke="DarkMagenta" StrokeThickness="2">
<Path.Data>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment x:Name="bezierSegment1" Point1="100,0" Point2="100,200" Point3="200,200" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard>
<PointAnimation Storyboard.TargetName="bezierSegment1" Storyboard.TargetProperty="Point1" From="0,0" To="100,0" />
<PointAnimation Storyboard.TargetName="bezierSegment1" Storyboard.TargetProperty="Point2" From="0,0" To="100,200" />
<PointAnimation Storyboard.TargetName="bezierSegment1" Storyboard.TargetProperty="Point3" From="0,0" To="200,200" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
I tried to put the storyboard into resources and begin outside from a Button_Click handler, but it doesn't helped.
Oh yes,yes.
EnableDependentAnimation is an important property to animations that allows you to animate your custom dependency properties. It’s handy, but not enough people know about it yet. Spread the word to save people from banging their heads against the wall!
Thank you Jerry Nixon: http://blog.jerrynixon.com/2012/06/windows-8-animated-pie-slice.html
Related
In my WPF application I have an animation of a certain element. The element to be animated looks like this.
<Path x:Name="theX" StrokeThickness="7" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<GeometryGroup>
<LineGeometry StartPoint="4, 4" EndPoint="60, 60"/>
<LineGeometry StartPoint="4, 60" EndPoint="60, 4"/>
</GeometryGroup>
</Path.Data>
</Path>
The color of the LineGeometry elements should be animated, but I don't know how the Storyboard.TargetProperty path is resolved. In this case the GeometryGroup element causes problems. How is the GeometryGroup element accommodated in the path of the Storyboard.TargetProperty, see the three "???".
I've already tried the following:
...).GeometryGroup.(... ...).(GeometryGroup.Children).(... ...).GeometryCollection.(... ... also i've tried that (Path.Stroke).(SolidColorBrush.Color)
<ColorAnimationUsingKeyFrames BeginTime="0:0:1" Duration="0:0:1"
Storyboard.TargetName="theX"
Storyboard.TargetProperty="(Path.Stroke).???.(SolidColorBrush.Color)"
FillBehavior="Stop">
<DiscreteColorKeyFrame Value="#333333" KeyTime="0:0:0"/>
<LinearColorKeyFrame Value="#6AFF00" KeyTime="0:0:0.2"/>
<DiscreteColorKeyFrame Value="#6AFF00" KeyTime="0:0:0.5"/>
<LinearColorKeyFrame Value="#333333" KeyTime="0:0:0.9"/>
</ColorAnimationUsingKeyFrames>
The Geometry-elements are part of a DataTemplat of an ItemsControl with data binding. And I get an exception on the .NET property linked via data binding.
The translation of the exception:
System.InvalidOperationException: "Not all property references in property path" (0) .GeometryGroup. (1) "can be resolved. Make sure that suitable objects support the properties."
In the application there is a similar element, an EllipseGeometry, in which the animation works in this way. The difference is the GeometryGroup element.
<Path x:Name="theO" StrokeThickness="6" Stroke="Transparent">
<Path.Data>
<EllipseGeometry Center="25, 25" RadiusX="22" RadiusY="22"/>
</Path.Data>
</Path>
<ColorAnimationUsingKeyFrames BeginTime="0:0:1" Duration="0:0:1"
Storyboard.TargetName="theO"
Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)"
FillBehavior="Stop">
<DiscreteColorKeyFrame Value="#333333" KeyTime="0:0:0"/>
<LinearColorKeyFrame Value="#FF4F00" KeyTime="0:0:0.2"/>
<DiscreteColorKeyFrame Value="#FF4F00" KeyTime="0:0:0.5"/>
<LinearColorKeyFrame Value="#333333" KeyTime="0:0:0.9"/>
</ColorAnimationUsingKeyFrames>
Many thanks for the help.
Notice in the working example you have a transparent brush set to the Stroke property.
But in the first example, nothing is set to this property.
Hence it is null.
And null has no properties to animate them.
You can explicitly set SolidColorBrush instance in this property, give this instance a name, and access its Color property directly.
It will be much easier than all these casts.
Example:
<Path x:Name="theX" StrokeThickness="7" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Stroke>
<SolidColorBrush x:Name="PathStroke" Color="Transparent"/>
</Path.Stroke>
<Path.Data>
<GeometryGroup>
<LineGeometry StartPoint="4, 4" EndPoint="60, 60"/>
<LineGeometry StartPoint="4, 60" EndPoint="60, 4"/>
</GeometryGroup>
</Path.Data>
</Path>
<ColorAnimationUsingKeyFrames BeginTime="0:0:1"
Duration="0:0:1"
Storyboard.TargetName="PathStroke"
Storyboard.TargetProperty="Color"
FillBehavior="Stop">
<DiscreteColorKeyFrame Value="#333333" KeyTime="0:0:0"/>
<LinearColorKeyFrame Value="#6AFF00" KeyTime="0:0:0.2"/>
<DiscreteColorKeyFrame Value="#6AFF00" KeyTime="0:0:0.5"/>
<LinearColorKeyFrame Value="#333333" KeyTime="0:0:0.9"/>
</ColorAnimationUsingKeyFrames>
Scenario as follows.
I have an canvas on which I want to move, lets say an rectangel, across the screen. The way the rectangle is supposed to move is determined by one specific path (like a railway, the rectangle is supposed to only move on the rails). The position on which the rectangle is currently located is provided by external source.
Current Location is provided every ~200-500ms.
So far I have tried the following:
simple TranslateTransform. Does the trick, but the rectangle jumps from Point a to b. No smooth Translation.
Storyboard with a doubleAnimation
Smoother, but the rectangle doesn´t follow the required path.
DoubleAnimationUsingPath. Rectangle is moving on the path. But now I am not able to provide the current position by external source.
Easiest for me would be a way to use an DoubleAnimationUsingPath and providing the X-Koordinate by external source.
But I am not sure if overall storyboards and animations are the best way to tackel that Problem.
If you know of any completely different Approach I am more than happy hear about it.
Kind regards
Just to get an idea of what can be done with animations, take a look at this little demo of a object moving along a track:
<Canvas>
<Canvas.Resources>
<PathGeometry x:Key="track">
<PathFigure StartPoint="200,100" IsClosed="True">
<LineSegment Point="300,100"/>
<ArcSegment SweepDirection="Clockwise"
Size="100,100" Point="300,300"/>
<LineSegment Point="200,300"/>
<ArcSegment SweepDirection="Clockwise"
Size="100,100" Point="200,100"/>
</PathFigure>
</PathGeometry>
</Canvas.Resources>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<MatrixAnimationUsingPath
Storyboard.TargetName="train"
Storyboard.TargetProperty="RenderTransform.Matrix"
PathGeometry="{StaticResource track}"
DoesRotateWithTangent="True"
Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Path Data="{StaticResource track}" Stroke="Black"
StrokeThickness="6"/>
<Path Data="{StaticResource track}" Stroke="White"
StrokeThickness="4" StrokeDashArray="2,2"/>
<Rectangle x:Name="train" Width="10" Height="6" Fill="Red"
Canvas.Left="-5" Canvas.Top="-3"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<MatrixTransform />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
Im recently working on some simple Imageviewer.
Now it came to my mind, it might be a nice feature, to do some context-sensitve actions like Zooming and rotating.
To implement these functions is not my problem, but the ContextMenu is.
I've decided to not use a ContextMenu-Element, instead im going to use a popup.
Reasons for PopUp:
Less Styling
Better Positioning
IsOpen is Bindable (ContextMenu is NOT bindable on IsOpen against all Articles regarding this)
Here comes the trouble:
<Image x:Name="PART_ImgCurrent" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Uniform" Grid.Row="0" Grid.Column="0"
Source="{Binding ElementName=PART_PreviewPanel, Path=SelectedItem.Source}">
<Image.LayoutTransform>
<RotateTransform Angle="0"></RotateTransform>
</Image.LayoutTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PART_ImgCurrent" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
<Popup IsHitTestVisible="False" Focusable="False" PlacementTarget="{Binding ElementName=PART_ImgCurrent}" AllowsTransparency="True" StaysOpen="True"
IsOpen="{Binding ElementName=PART_ImgCurrent, Path=IsMouseOver, Mode=OneWay}"
Placement="Right" HorizontalOffset="-42" VerticalOffset="2">
<StackPanel Opacity="0.5" VerticalAlignment="Stretch">
<Button Content="Ugly Button" Height="40" Width="40"></Button>
<Button Content="Ugly Button" Height="40" Width="40"></Button>
<Button Content="Ugly Button" Height="40" Width="40"></Button>
</StackPanel>
</Popup>
As you can see, im binding IsOpen of Popup to IsMouseOver on Image which results in a funny Disco-BlinkenLights-Behavior when i try to click a button inside the Popup.
What has this to do with the Title?
AcrobatReader has this
This is almost exactly the behavior im looking for. How is this thing called?
Or had someone ever similar issues and could provide a solution?
Sorry for the delay, soon as I thought I had a second I got busy again. Anyway, here's one of several ways I can think of accomplishing your goal, give it a shot. I sort of assumed it may not be just images you want this for and if you threw the resource stuff in a dictionary and kept your naming consistent (or even better, just target the nested UIElement) you could use it all over the place. Notice the Grid is acting as what would be the Image in this example.
I generally make things open for future added interactions and stuff, so in this case I would probably just make the image source the background brush for Grid or place it as a child. That way if you decide to add other objects in there or say other effects and stuff you've got a good start point.
Anyway I digress, so try out the concept example below and see if it's what you're after. If not, like I said there's several other ways I can think of to accomplish your goal so just let me know. :)
<!-- HitTestVisibility Area -->
<Grid x:Name="ImagePlaceholder"
Height="500" Width="500"
Background="LightBlue">
<Grid.Resources>
<Storyboard x:Key="OnMouseEnter">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="FakePopUp">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnMouseLeave">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="FakePopUp">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<Grid.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource OnMouseEnter}"/>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard Storyboard="{StaticResource OnMouseLeave}"/>
</EventTrigger>
</Grid.Triggers>
<!-- Overlay -->
<Border Name="FakePopUp" Visibility="Collapsed"
Margin="0,0,0,25" Background="SlateGray"
Height="50" CornerRadius="20" Padding="10"
HorizontalAlignment="Center" VerticalAlignment="Bottom">
<StackPanel Orientation="Horizontal">
<Button Content="Eins Bier"/>
<Button Content="Zwei Bier" Margin="10,0"/>
<Button Content="Drei Bier"/>
</StackPanel>
</Border>
</Grid>
I went with Storyboards attached to the parent instead of direct triggers with TargetName like I said, because I could think of a bunch of other instances features might want to be added that would make sense. Even something simple like adding a transition duration for a nice fade effect or maybe a translate y to slide it up while fading etc, etc, etc.
Anyway, hope this helps. Cheers!
I have code something like this:
<Path x:Name="arrow" StrokeThickness="3" Stroke="Black" Data="M34,115 C45,106 91,119 105,112 119,105 172,75.004352 188,82.003591" />
what I want is to animate the Data property of the path. I'm searching this from last two days didn't find a solution.
what I actually want is to show path bit by bit.
Does anyone have any Idea?
"what I actually want is to show path bit by bit"
Do you mean something like this?
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" >
<Grid.Resources>
<Storyboard x:Key="CWTrace">
<!-- To run opposite direction, just swap the 'From' and 'To' values. -->
<DoubleAnimation BeginTime="00:00:0.5" RepeatBehavior="Forever"
Storyboard.TargetName="arrow"
Storyboard.TargetProperty="StrokeDashOffset"
Duration="0:0:5" From="100" To="0"/>
</Storyboard>
</Grid.Resources>
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource CWTrace}"/>
</EventTrigger>
</Grid.Triggers>
<Path x:Name="arrow"
StrokeDashOffset="0" StrokeDashArray="100"
StrokeThickness="3" Stroke="Black"
Data="M34,115 C45,106 91,119 105,112 119,105 172,75.004352 188,82.003591"/>
</Grid>
Obviously remove the RepeatBehavior for a one time anim, and tinker with values to get exactly what you're after. Cheers.
I'd like to create a glimmer animation on path's stroke in the direction of the path
My code looks like this:
<Path StrokeThickness="2">
<Path.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard Duration="0:0:3" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="firstGradientStop"
Storyboard.TargetProperty="Offset"
From="-0.2" To="1.0" Duration="0:0:2" />
<DoubleAnimation
Storyboard.TargetName="middleGradientStop"
Storyboard.TargetProperty="Offset"
From="-0.1" To="1.1" Duration="0:0:2" />
<DoubleAnimation
Storyboard.TargetName="lastGradientStop"
Storyboard.TargetProperty="Offset"
From="0" To="1.2" Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
<Path.Stroke>
<LinearGradientBrush>
<GradientStop Color="#80000000" x:Name="firstGradientStop" Offset="0.4" />
<GradientStop Color="White" x:Name="middleGradientStop" Offset="0.5" />
<GradientStop Color="#80000000" x:Name="lastGradientStop" Offset="0.6" />
</LinearGradientBrush>
</Path.Stroke>
<Path.Data>
<!-- dynamic data here, sample path below -->
<GeometryGroup>
<LineGeometry StartPoint="0,0" EndPoint="100,100" />
<LineGeometry StartPoint="100,100" EndPoint="200,100" />
</GeometryGroup>
</Path.Data>
</Path>
the problem is that the animation is independent of the direction of path and I need the glow to go in the direction from StartPoint to EndPoint. Is this achievable?
You can use StartPoint and EndPoint of linearGradientBrush, something like that (play with values, so you can rotate angle of gradient like you want whenever you want):
<PointAnimation
Storyboard.TargetName="Brush"
Storyboard.TargetProperty="StartPoint"
From="0,0" To="0.5,0" Duration="0:0:1.5" />
<PointAnimation
Storyboard.TargetName="Brush"
Storyboard.TargetProperty="EndPoint"
From="1,1" To="0.5,1" Duration="0:0:1.5" />
But it's not a solution for complex dynamic path. (And that's limitations of stroke cause it's nothing more than background and you can't glimmer with it self-intersecting paths)
If you need more, then create a simple UserControl that will represent just a straight line with proper animation. After that you need to add that controls(with proper rotateTransform) to canvas from codeBehind iterating by path structure and set needed storyboards timeline. That would be a complete solution.