2

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

Mikk
  • 331
  • 4
  • 13

1 Answers1

8

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!

Community
  • 1
  • 1
Chris W.
  • 22,835
  • 3
  • 60
  • 94
  • hi chris, thanks for the quick reply! (how did you manage to even create an animation so fast?) yeah its exactly what I meant: to even apply the gradient to a single dash. I already thought that that wouldn't be possible so easy. The gradient animation instead of a dash is a cool trick but would it be possible to shorten it to a only a fraction of one side of the rectangle at a time? something like [this](http://imgur.com/z9UD2DQ) – Mikk Apr 06 '16 at 19:22
  • Yea you can, except you would need another Rectangle overlaying to "lead" the gradient below it to achieve that exact result using 2 `GradientStop` points on the overlay to give the fine edge followed by transparent trail provided by the stroke underneath it. Whenever you're doing stuff like this I definitely recommend using Blend (formerly Expression Blend) that comes with Visual Studio. It makes life sooooo much easier once you learn parts like the timeline recorder features etc. If you'll require another example of this using stroke/gradients etc I'll have to do it another time though. – Chris W. Apr 06 '16 at 19:32
  • @Mikk See my updated answer. I generally have a time threshold on answers before I realize I should probably be charging consulting fees, you're at about 10 minutes total so far so no worries. :) – Chris W. Apr 06 '16 at 19:46
  • thanks for the update! .. I guess I got the main idea even though its still not looking quite right. but I will take your advice and take a look at Blend (never touched it yet really before) and play with the two rectangles. I'm not too sure tho yet about how to get the corners right with the gradients (especially when there are round corners) .. but then again it's maybe not necessary to be too exact when its in motion anyway. ps: you def. should charge for the short response times! :) – Mikk Apr 06 '16 at 22:29
  • @Mikk When you're dealing with Stroke it won't matter whether the corners are rounder, or angle, or even some crazy shape from a `Path` geometry. If I come up with some more free time later I'll tweak it more to get it more on set with what you're after. For now though I would say you may way want to tinker for a bit and if you feel I answered sufficiently for now mark this one as such and ask another later with more specifics towards whatever roadblocks you encounter along the way. In the meantime, I'm off to do more work away from a screen. Cheers amigo! – Chris W. Apr 06 '16 at 23:07
  • sounds good! thanks again for your help. i will check it out on the weekend and see how far i can get with Blend. – Mikk Apr 07 '16 at 16:22