How can I animate a Clipping Path - wpf

I am trying to animate a clipping path. I read from Mask Animations (Clipping Path Animations) In Silverlight Without a Line of Code that I should animate the clipping path 1st so
Data=”M159.67175,104.26108 L177.91812,28.328932 L195.51648,104.43327 L255.0802,102.6104 L206.86984,151.82758 L225.8029,226.56477 L179.0616,179.17046 L129.73396,229.29906 L147.97842,150.63879 L98.650803,101.53297 z”
will be changed to
<Path.Data>
<PathGeometry>
<PathFigure IsClosed=”True” StartPoint=”91.0527648925781,84.0121078491211?>
<LineSegment Point=”118.057907104492,0.549586236476898?/>
<LineSegment Point=”144.103973388672,84.2013778686523?/>
<LineSegment Point=”232.259979248047,82.1977386474609?/>
<LineSegment Point=”160.907287597656,136.2958984375?/>
<LineSegment Point=”188.928756713867,218.444961547852?/>
<LineSegment Point=”119.750289916992,166.350433349609?/>
<LineSegment Point=”46.7439804077148,221.450408935547?/>
<LineSegment Point=”73.7462997436523,134.989212036133?/>
<LineSegment Point=”0.740016639232636,81.0134506225586?/>
</PathFigure>
</PathGeometry>
</Path.Data>
but after animating the path, my XAML still looks like
<Path x:Name="path" Data="M0.5,0.5 L84.5,0.5 L84.5,150.5 L0.5,150.5 z" HorizontalAlignment="Left" Height="151" Margin="76,55,0,0" Stretch="Fill" Stroke="{x:Null}" VerticalAlignment="Top" Width="85" Fill="Black" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
A short video on the problem http://screenr.com/1Wc

You need to create the clipping path prior to doing the animation.
Then, use the Direct Select tool (the second arrow down on the toolbar in Blend 4) to select the clipping path. Moving the clipping path while recording a timeline will result in the clipping being animated the way you expect.
Here's the XAML from two rectangles - a big one with a linear gradient, and a smaller one that is the clipping path. The clipping rectangle is animated and follows the gradient.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="WpfSplash.TemplatePanel"
x:Name="UserControl" Height="1000" Width="544">
<UserControl.Resources>
<Storyboard x:Key="OnLoaded1">
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(LineSegment.Point)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="495,184.5"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(LineSegment.Point)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="-14.9999999999998,184.5"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.StartPoint)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="-14.9999999999998,142.5"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(LineSegment.Point)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="495,142.5"/>
</PointAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource OnLoaded1}"/>
</EventTrigger>
</UserControl.Triggers>
<Canvas x:Name="LayoutRoot">
<Rectangle x:Name="rectangle" Height="207" Canvas.Left="33" Canvas.Top="106.5" Width="481.5">
<Rectangle.Clip>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="-15,16.5">
<LineSegment Point="495,16.5"/>
<LineSegment Point="495,54"/>
<LineSegment Point="-15,54"/>
</PathFigure>
</PathGeometry>
</Rectangle.Clip>
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD6904A" Offset="1"/>
<GradientStop Color="#FFEBD8FF"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>

Related

WPF Animation - Rotate elements on button click

I want to rotate two elements from 0 to angles: 1. Element (ClampL) 45 angle and 2. Element (ClampR) -45 Angle, but they should move together. The elements are 2 clamps which are open and when they grab something, they close and this process should happen on button click.
Here is my XAML:
<UserControl x:Class="WPF_AnimatedLift.View.Prozess"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPF_AnimatedLift.View" xmlns:viewmodel="clr-namespace:WPF_AnimatedLift.ViewModel"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="1000">
<Canvas x:Name="canvas" Margin="0,0,-163,-83">
<Path x:Name="ClampR" Fill="#FF000000" StrokeThickness="2.12787" Data="M 524.2207 473.57227 L 524.2207 563.57227 L 137.14258 563.57227 L 137.14258 652.14258 L 571.42773 652.14258 L 571.42773 563.57227 L 571.36328 563.57227 L 571.36328 473.57227 L 524.2207 473.57227 z " Height="68.668" Stretch="Fill" Width="80.734" Canvas.Left="411.375" Canvas.Top="339.125" >
<Path.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ClampR"
Storyboard.TargetProperty="LayoutTransform.(RotateTransform.Angle)"
From="0"
To="360"
Duration="0:0:5"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
<Path.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleY="0.265" ScaleX="0.265"/>
<SkewTransform/>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</Path.LayoutTransform>
</Path>
<Path x:Name="ClampL" Fill="#FF000000" StrokeThickness="2.12787" Data="M 110 344.28516 L 110 434.28516 L 110 485.71484 L 110 522.85742 L 544.28516 522.85742 L 544.28516 434.28516 L 157.14258 434.28516 L 157.14258 344.28516 L 110 344.28516 z " Height="68.668" Stretch="Fill" Width="80.734" Canvas.Left="384.508" Canvas.Top="339.166">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="0.265" ScaleX="0.265"/>
<SkewTransform/>
<RotateTransform Angle="45"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
<Button Content="START" Canvas.Left="84" Canvas.Top="403" Width="106" Height="48" FontSize="30" FontWeight="Bold" Name="BtnStart" Command="{Binding ClickCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click"> //???
<BeginStoryboard Storyboard="{StaticResource Storyboard}" />
</EventTrigger>
</Button.Triggers>
</Button>
</Canvas>
<UserControl.DataContext>
<viewmodel:ProzessViewModel/>
</UserControl.DataContext>
</UserControl>
As you can see in code, I tried with Path.Trigger, DoubleAnimation, but it doesn't work, can someone help me?
Thank you.
Basically, in EventTrigger, you can only refer the elements that exist inside that FrameworkElement. The solution would be different depending on where you want to set EventTrigger.
1. Button
You can use EventTrigger in the Button, which is the source of Button.Click event, like the following. The elements are simplified to a minimum for brevity and the Storyboard.TargetProperty is modified to circumvent TransformGroup.
<Canvas x:Name="canvas">
<Path x:Name="ClampR"
Canvas.Left="411" Canvas.Top="339"
Width="80" Height="68"
Fill="Black"
Data="M 0,0 1,0 0,1 z" Stretch="Fill">
<Path.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleY="0.265" ScaleX="0.265"/>
<SkewTransform/>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</Path.LayoutTransform>
</Path>
<Button x:Name="BtnStart"
Canvas.Left="84" Canvas.Top="403"
Width="106" Height="48"
Content="START">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ClampR"
Storyboard.TargetProperty="LayoutTransform.Children[2].Angle"
From="0" To="360"
Duration="0:0:5"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Canvas>
2. Canvas
As Button.Click is RoutedEvent and propagated to the root, you can use EventTrigger at parent level. In this case, at Canvas.Triggers.
<Canvas x:Name="canvas">
<Canvas.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ClampR"
Storyboard.TargetProperty="LayoutTransform.Children[2].Angle"
From="0" To="360"
Duration="0:0:5"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Path x:Name="ClampR"
Canvas.Left="411" Canvas.Top="339"
Width="80" Height="68"
Fill="Black"
Data="M 0,0 1,0 0,1 z" Stretch="Fill">
<Path.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleY="0.265" ScaleX="0.265"/>
<SkewTransform/>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</Path.LayoutTransform>
</Path>
<Button x:Name="BtnStart"
Canvas.Left="84" Canvas.Top="403"
Width="106" Height="48"
Content="START"/>
</Canvas>
3. Path
Unlike standard EventTrigger, EventTrigger of Microsoft.Xaml.Behaviors.Wpf is more robust and can refer other controls. Thus it can work in the Path.
Add xmlns:i="http://schemas.microsoft.com/xaml/behaviors" in header.
<Canvas x:Name="canvas">
<Path x:Name="ClampR"
Canvas.Left="411" Canvas.Top="339"
Width="80" Height="68"
Fill="Black"
Data="M 0,0 1,0 0,1 z" Stretch="Fill">
<i:Interaction.Triggers>
<i:EventTrigger SourceName="BtnStart" EventName="Click">
<i:ControlStoryboardAction>
<i:ControlStoryboardAction.Storyboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Rotation"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0" To="360"
Duration="0:0:5"
RepeatBehavior="Forever"/>
</Storyboard>
</i:ControlStoryboardAction.Storyboard>
</i:ControlStoryboardAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<Path.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleY="0.265" ScaleX="0.265"/>
<SkewTransform/>
<RotateTransform x:Name="Rotation" CenterX="0.5" CenterY="0.5" Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</Path.LayoutTransform>
</Path>
<Button x:Name="BtnStart"
Canvas.Left="84" Canvas.Top="403"
Width="106" Height="48"
Content="START"/>
</Canvas>

Storyboard EllipseGeometry animation

all. I have started a simple WPF application and would like a button to follow an elliptical path when it is made visible(for now I just want it to occur when I click...for testing purposes). It should simply move along the path then come to rest at the final point. I am having trouble getting the storyboard to work in a style. It won't reference the path that I have already defined. How do I resolve this? Eventually, each button will need to have it's own final resting point, so I will need to pass in an extra animation at a later date. The code is in XAML(posted below).
<Window x:Class="EllipseFollowsPath.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EllipseFollowsPath"
mc:Ignorable="d"
Title="MainWindow" Height="768" Width="1366">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="768" Width="1366">
<Grid.Resources>
<PathGeometry x:Key="path">
<PathGeometry.Figures>
<PathFigure StartPoint="921,384" IsClosed="False">
<ArcSegment Point="445,384" Size="60 60"
SweepDirection="Counterclockwise"/>
</PathFigure>
<PathFigure StartPoint="445,384" IsClosed="False">
<ArcSegment Point="921,384" Size="60 60"
SweepDirection="Counterclockwise"/>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
<Storyboard x:Key="sb" RepeatBehavior="Forever">
<MatrixAnimationUsingPath
Storyboard.TargetName="transform"
Storyboard.TargetProperty="Matrix"
PathGeometry="{StaticResource path}"
Duration="0:0:2">
</MatrixAnimationUsingPath>
</Storyboard>
</Grid.Resources>
<Button Height="20" Width="20">
<Button.RenderTransform>
<MatrixTransform x:Name="transform"/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard Storyboard="{StaticResource sb}">
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
The code below works...
<Window x:Class="EllipseFollowsPath.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EllipseFollowsPath"
mc:Ignorable="d"
Title="MainWindow" Height="768" Width="1366">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="768" Width="1366">
<Grid.Resources>
<PathGeometry x:Key="path">
<PathGeometry.Figures>
<PathFigure StartPoint="921,384" IsClosed="False">
<ArcSegment Point="445,384" Size="60 60"
SweepDirection="Counterclockwise"/>
</PathFigure>
<PathFigure StartPoint="445,384" IsClosed="False">
<ArcSegment Point="921,384" Size="60 60"
SweepDirection="Counterclockwise"/>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
<Storyboard x:Key="sb" RepeatBehavior="Forever">
<MatrixAnimationUsingPath
Storyboard.TargetName="transform"
Storyboard.TargetProperty="Matrix"
PathGeometry="{StaticResource path}"
Duration="0:0:2">
</MatrixAnimationUsingPath>
</Storyboard>
</Grid.Resources>
<Button Height="20" Width="20">
<Button.RenderTransform>
<MatrixTransform x:Name="transform"/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard Storyboard="{StaticResource sb}">
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>

Animation Rotating a PathGeometry

I have a path that has three defining PathGeometries: a circle, a connecting line, and a path that represents fan blades. I'd like to use the path's Tag property to trigger an animation that rotates the fan blade geometry. Since I need to reuse this many times, I'd also like to encompass the path and storyboard in a single style, if possible.
So far I've built up the paths, created a storyboard, created a rotate transform on the PathGeometry that I'd like to rotate, and created the necessary trigger.
I cannot figure out why the following does not work:
<Style x:Key="fanPath" TargetType="{x:Type Path}">
<Setter Property="Stroke" Value="Black"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Data">
<Setter.Value>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="15,30" IsFilled="False">
<LineSegment Point="15,50"/>
</PathFigure>
</PathGeometry>
<EllipseGeometry Center="15,15" RadiusX="15" RadiusY="15"/>
<!-- Want to rotate the following -->
<PathGeometry>
<PathGeometry.Transform>
<RotateTransform x:Name="rotate" CenterX="15" CenterY="15"/>
</PathGeometry.Transform>
<PathFigure StartPoint="10,5" IsClosed="True">
<LineSegment Point="20,5"/>
<LineSegment Point="10,25"/>
<LineSegment Point="20,25"/>
</PathFigure>
<PathFigure StartPoint="5,10" IsClosed="True">
<LineSegment Point="5,20"/>
<LineSegment Point="25,10"/>
<LineSegment Point="25,20"/>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Tag" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="fanRotate">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="rotate.Angle" From="0"
To="90" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="fanRotate"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
I've checked that my Tag property is being set properly and I've checked that manually changing the Angle property of the rotate transform works as expected. I believe my problem lies in linking the Storyboard.TargetProperty property to the proper place (rotate.Angle), but I cannot figure out what core issue I'm encountering.
You need to access your Angle property via a path as follows:
Storyboard.TargetProperty="(Path.Data).(GeometryGroup.Children)[2].(PathGeometry.Transform).Angle"
This does what you need:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="fanPath" TargetType="{x:Type Path}">
<Setter Property="Stroke" Value="Black"/>
<Setter Property="StrokeThickness" Value="1"/>
<Setter Property="Data">
<Setter.Value>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="15,30" IsFilled="False">
<LineSegment Point="15,50"/>
</PathFigure>
</PathGeometry>
<EllipseGeometry Center="15,15" RadiusX="15" RadiusY="15"/>
<!-- Want to rotate the following -->
<PathGeometry>
<PathGeometry.Transform>
<RotateTransform x:Name="rotate" CenterX="15" CenterY="15"/>
</PathGeometry.Transform>
<PathFigure StartPoint="10,5" IsClosed="True">
<LineSegment Point="20,5"/>
<LineSegment Point="10,25"/>
<LineSegment Point="20,25"/>
</PathFigure>
<PathFigure StartPoint="5,10" IsClosed="True">
<LineSegment Point="5,20"/>
<LineSegment Point="25,10"/>
<LineSegment Point="25,20"/>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Tag" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="fanRotate">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Path.Data).(GeometryGroup.Children)[2].(PathGeometry.Transform).Angle" From="0"
To="90" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="fanRotate"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Path x:Name="paththing" Width="300" Height="300" Fill="Aqua" Stretch="Fill" Style="{StaticResource fanPath}"/>
<Button Grid.Row="1" x:Name="button" Content="Go" VerticalAlignment="Bottom">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="paththing" Storyboard.TargetProperty="Tag">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="True"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>

How to animate WPF rectangle Width and Fill property at the same time

I have a rectangle for which I want to animate the Width from 0 to some offset with a color say Red and the remaining width with different color say Green.
Any idea how to do it?
Example:
Animation flow ->
|start <- Red -> stop | start <- Green -> stop|
Rectangle doesnt allow you have Content in it. So, you can use Fill as a VisualBrush or DrawingBrush.
VisualBrush approach
This VisualBrush will have a StackPanel with two Rectangle objects.
Run below code as it is :
<Rectangle Height="100" Stroke="Black">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" From="0" To="200" Duration="0:0:10"/>
<DoubleAnimation Storyboard.TargetName="LeftRect" Storyboard.TargetProperty="Width" From="0" To="100" Duration="0:0:5"/>
<DoubleAnimation Storyboard.TargetName="RightRect" Storyboard.TargetProperty="Width" From="0" To="100" Duration="0:0:5" BeginTime="0:0:5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
<Rectangle.Fill>
<VisualBrush Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<StackPanel Orientation="Horizontal">
<Rectangle x:Name="LeftRect" Height="100">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Red"/>
<Setter Property="Width" Value="0"/>
</Style>
</Rectangle.Style>
</Rectangle>
<Rectangle x:Name="RightRect" Height="100">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Green"/>
<Setter Property="Width" Value="0"/>
</Style>
</Rectangle.Style>
</Rectangle>
</StackPanel>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
DrawingBrush approach
This DrawingBrush will have RectangleGeometry and won't use any Control.
<Rectangle Height="100" Width="300" Stroke="Black" StrokeThickness="2" RenderTransformOrigin="0,0.5">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="LeftScaleX" Storyboard.TargetProperty="ScaleX" From="0" To="1" Duration="0:0:1"/>
<DoubleAnimation Storyboard.TargetName="RightScaleX" Storyboard.TargetProperty="ScaleX" From="0" To="1" Duration="0:0:1" BeginTime="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
<Rectangle.Fill>
<DrawingBrush AlignmentX="Left" Stretch="None">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Red">
<GeometryDrawing.Geometry>
<RectangleGeometry x:Name="LeftRect" Rect="0 0 200 100">
<RectangleGeometry.Transform>
<TransformGroup>
<ScaleTransform x:Name="LeftScaleX" ScaleX="0" CenterY="50"/>
</TransformGroup>
</RectangleGeometry.Transform>
</RectangleGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="Green">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="200 0 300 100">
<RectangleGeometry.Transform>
<TransformGroup>
<ScaleTransform x:Name="RightScaleX" ScaleX="0" CenterX="200"/>
</TransformGroup>
</RectangleGeometry.Transform>
</RectangleGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
A much simpler approach would be to animate ViewPort property.
<Rectangle Stroke="Black" Margin="44,67,44,0" Width="0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="100">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="300" Duration="0:0:1"/>
<RectAnimation Storyboard.TargetName="Brush1" Storyboard.TargetProperty="(DrawingBrush.Viewport)" To="0,0, 300,100" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
<Rectangle.Fill>
<DrawingBrush x:Name="Brush1" Viewport="0,0,0,100" AlignmentX="Left" Stretch="None" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Red">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0, 200, 100"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="Green">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="200,0, 100, 100"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>

WPF simple brush animation causes a performance issue

I've created a simple animation that rotates a linear gradient brush used as a background for an ellipse. I used it on 4 ellipses, and it takes about 6% CPU in average alone. Is there any way I can improve the performance? (Parts of the ellipses are hidden on purpose).
<Window x:Class="MyAnimation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:testDisplayAccessPoints="clr-namespace:TestDisplayAccessPoints"
xmlns:zoomAndPan="clr-namespace:ZoomAndPan;assembly=ZoomAndPan"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="1100"
Width="1100">
<Window.Resources>
<Storyboard x:Key="Storyboard1" RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseLow"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseMedium"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseHigh"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseVeryHigh"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<Grid x:Name="BackgroundGrid" Background="Black">
<Ellipse x:Name="ellipseLow" HorizontalAlignment="Left" Height="800" Margin="-720,0,0,0" StrokeThickness="5" VerticalAlignment="Center" Width="1600">
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="90" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Gold" Offset="0.2"/>
<GradientStop Color="Gold" Offset="0.8"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Ellipse x:Name="ellipseMedium" HorizontalAlignment="Left" Height="600" Margin="-520,0,0,0" StrokeThickness="5" VerticalAlignment="Center" Width="1200">
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="90" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Gold" Offset="0.2"/>
<GradientStop Color="Gold" Offset="0.8"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Ellipse x:Name="ellipseHigh" HorizontalAlignment="Left" Height="400" Width="800" Margin="-320,0,0,0" StrokeThickness="5" VerticalAlignment="Center" >
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="90" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Gold" Offset="0.2"/>
<GradientStop Color="Gold" Offset="0.8"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Ellipse x:Name="ellipseVeryHigh" HorizontalAlignment="Left" Height="200" Margin="-120,0,0,0" StrokeThickness="5" VerticalAlignment="Center" Width="400">
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="90" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Gold" Offset="0.2"/>
<GradientStop Color="Gold" Offset="0.8"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
</Grid>
</Window>
I am not sure whether it will have impact on performance but for readability for sure. One style for all eclipse elements, one resource for stroke etc.
<Window.Resources>
<Storyboard x:Key="Storyboard1" RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseLow"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseMedium"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseHigh"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
<DoubleAnimation Storyboard.TargetProperty="(Shape.Stroke).(Brush.RelativeTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ellipseVeryHigh"
Timeline.DesiredFrameRate="12" From="0" To="359" Duration="0:00:3.0" />
</Storyboard>
<LinearGradientBrush x:Key="LinearBrush1" EndPoint="0.5,1" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="90" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Gold" Offset="0.2"/>
<GradientStop Color="Gold" Offset="0.8"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
<Style TargetType="Ellipse">
<Setter Property="Stroke" Value="{StaticResource LinearBrush1}"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="StrokeThickness" Value="5"/>
</Style>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<Grid x:Name="BackgroundGrid" Background="Black">
<Ellipse x:Name="ellipseLow" Height="800" Margin="-720,0,0,0" Width="1600"/>
<Ellipse x:Name="ellipseMedium" Height="600" Margin="-520,0,0,0" Width="1200"/>
<Ellipse x:Name="ellipseHigh" Height="400" Width="800" Margin="-320,0,0,0"/>
<Ellipse x:Name="ellipseVeryHigh" Height="200" Margin="-120,0,0,0" Width="400"/>
</Grid>

Resources