Mikk
Mikk

Reputation: 331

How to put a gradient on a rectangle stroke and animate it?

I was playing around with WPF animations and tried to animate the border of a rectangle in the way of a wandering stroke (kind of marching ants with only one ant) and came up with the following working code:

<Window
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="WindowTest.MainWindow"
    Height="454.719" Width="429.847" ResizeMode="NoResize">
<Window.Resources>
    <Storyboard x:Key="MarchingAnts">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
            Storyboard.TargetName="rectangle" 
            Storyboard.TargetProperty="(Shape.StrokeDashOffset)" 
            RepeatBehavior="Forever">
            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
            <SplineDoubleKeyFrame KeyTime="00:00:03.000000" Value="-385"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Window.Triggers>
    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
        <BeginStoryboard Storyboard="{StaticResource MarchingAnts}"/>
    </EventTrigger>
</Window.Triggers>

<Grid x:Name="LayoutRoot">
    <Canvas x:Name="canvas" Background="#FF262626">
        <Rectangle Fill="#14FFFFFF" 
            Stroke="Red"
            x:Name="rectangle" Width="400" Height="400" 
            StrokeDashOffset="-385" StrokeDashArray='0, 0, 100,285' StrokeThickness="4"                        
            RadiusX="25" RadiusY="25"
            Canvas.Left="10" Canvas.Top="10">                
        </Rectangle>
    </Canvas>
</Grid>
</Window>

So I have basically one 'ant' with the length of 100 wandering around a square with a width of 400. Now I wanted to find a way to put a gradient on the 'ant', for example to fade it out from 50% to the end.

Is there a way to add such to the animated StrokeDashArray or should I create the whole thing differently from the beginning? Requirement would be to have the animation on top of a border or rectangle.

Any hints are welcome!

update: as in Chris answer and my comment .. the intended look would be like this: example with the dash wandering around the rectangle

Upvotes: 2

Views: 3943

Answers (1)

Chris W.
Chris W.

Reputation: 23280

I have an example of ants here

You can apply a Gradient to your stroke, as example;

<Rectangle.Stroke>
   <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
      <GradientStop Color="Red" Offset="0"/>
      <GradientStop Color="Transparent" Offset="1"/>
   </LinearGradientBrush>
</Rectangle.Stroke>

However it will apply the gradient to the entire stroke and not an individual dash as I think you're implying you would rather have. What you're asking for there is not possible.

However, you can fake it with an illusion to sort of the same effect without the DashArray and animating the Gradient EndPoint and StartPoint (Shown in the Rectangle.Stroke example above) around the object from start to finish.

Quickie Concept Example:

<Window x:Class="WpfApplication1.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:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Storyboard x:Key="GradientChaser" RepeatBehavior="Forever">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.StartPoint)" 
                                          Storyboard.TargetName="rectangle">
                <EasingPointKeyFrame KeyTime="0:0:0.5" Value="0.855,0.148"/>
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.852,0.855"/>
                <EasingPointKeyFrame KeyTime="0:0:1.5" Value="0.148,0.855"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.144,0.149"/>
                <EasingPointKeyFrame KeyTime="0:0:2.5" Value="0,0"/>
            </PointAnimationUsingKeyFrames>
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.EndPoint)" 
                                          Storyboard.TargetName="rectangle">
                <EasingPointKeyFrame KeyTime="0:0:0.5" Value="0.145,0.852"/>
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.148,0.145"/>
                <EasingPointKeyFrame KeyTime="0:0:1.5" Value="0.852,0.145"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.856,0.851"/>
                <EasingPointKeyFrame KeyTime="0:0:2.5" Value="0,1"/>
            </PointAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource GradientChaser}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>

        <Rectangle x:Name="rectangle" Width="250" Height="250"
                   HorizontalAlignment="Center" VerticalAlignment="Center" 
                   StrokeThickness="10">
            <Rectangle.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Red" Offset="0"/>
                    <GradientStop Color="Transparent" Offset="1"/>
                </LinearGradientBrush>
            </Rectangle.Stroke>

        </Rectangle>

    </Grid>
</Window>

Quickie Concept Example Result:

animated xaml stroke example

ADDENDUM:

Unfortunately I don't have free time to tweak it and make it perfect to do your work but hopefully it will communicate the concept of how you can achieve the effect with the stroke gradient technique you're after.

Quickie Updated code:

<Window x:Class="WpfApplication1.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:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Storyboard x:Key="GradientChaser" RepeatBehavior="Forever">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.StartPoint)" Storyboard.TargetName="rectangle">
                <EasingPointKeyFrame KeyTime="0:0:0.5" Value="0.855,0.148"/>
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.852,0.855"/>
                <EasingPointKeyFrame KeyTime="0:0:1.5" Value="0.148,0.855"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.144,0.149"/>
                <EasingPointKeyFrame KeyTime="0:0:2.5" Value="0,0"/>
            </PointAnimationUsingKeyFrames>
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.EndPoint)" Storyboard.TargetName="rectangle">
                <EasingPointKeyFrame KeyTime="0:0:0.5" Value="0.145,0.852"/>
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.148,0.145"/>
                <EasingPointKeyFrame KeyTime="0:0:1.5" Value="0.852,0.145"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.856,0.851"/>
                <EasingPointKeyFrame KeyTime="0:0:2.5" Value="0,1"/>
            </PointAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="GradientChaserOverlay" RepeatBehavior="Forever">
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.StartPoint)" Storyboard.TargetName="rectangle2">
                <EasingPointKeyFrame KeyTime="0:0:0.5" Value="0.146,0.146"/>
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.502,-0.001"/>
                <EasingPointKeyFrame KeyTime="0:0:1.5" Value="0.85,0.142"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.863,0.845"/>
                <EasingPointKeyFrame KeyTime="0:0:2.5" Value="-0.001,0.498"/>
            </PointAnimationUsingKeyFrames>
            <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.EndPoint)" Storyboard.TargetName="rectangle2">
                <EasingPointKeyFrame KeyTime="0:0:0.5" Value="0.854,0.854"/>
                <EasingPointKeyFrame KeyTime="0:0:1" Value="0.498,1.001"/>
                <EasingPointKeyFrame KeyTime="0:0:1.5" Value="0.15,0.858"/>
                <EasingPointKeyFrame KeyTime="0:0:2" Value="0.137,0.155"/>
                <EasingPointKeyFrame KeyTime="0:0:2.5" Value="1.001,0.502"/>
            </PointAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource GradientChaser}"/>
            <BeginStoryboard Storyboard="{StaticResource GradientChaserOverlay}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>

        <Rectangle x:Name="rectangle" Width="250" Height="250" HorizontalAlignment="Center" VerticalAlignment="Center" StrokeThickness="10">
            <Rectangle.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Red" Offset="0"/>
                    <GradientStop Color="Transparent" Offset="1"/>
                </LinearGradientBrush>
            </Rectangle.Stroke>

        </Rectangle>

        <Rectangle x:Name="rectangle2" Width="250" Height="250" HorizontalAlignment="Center" VerticalAlignment="Center" StrokeThickness="10">
            <Rectangle.Stroke>
                <LinearGradientBrush EndPoint="1,0.501" StartPoint="0,0.499">
                    <GradientStop Color="White" Offset="0.35"/>
                    <GradientStop Color="Transparent" Offset="0.342"/>
                </LinearGradientBrush>
            </Rectangle.Stroke>

        </Rectangle>

    </Grid>
</Window>

Quickie Concept Result (will require some tweaking, but hey, SO isn't a free code work service anyway right? :) Oh, and sorry for the crappy .gif quality.

enter image description here

Hope this helps, Cheers!

Upvotes: 8

Related Questions