Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF animate StrokeDashArray

Tags:

animation

wpf

I'm trying to create an animation in WPF but I'm quite confused about where to place everything.. I need a circle that grows, like drawing himself.

To do so I have a nicely designed circle (one stroked circle with a blured stroked clircle below) Then I have another circle with StrokeDashArray. I plan to use this circle as a opacityMask for the first ones and animate the StrokeDashArray to reveal the circ.

Ive been playing around and I can modify the StrokeDashArray from [0, 100] to [50 100] and I get a growing line covering the circle (I really don't inderstand where the 0 100 and the 50 100 came from.. just tried until it looks nice.

So now my problem is where to distribute the stuff.

my code so far looks like:

<UserControl bla bla bla bla>
    <!-- The mask that should be animated -- >
    <Ellipse Name="Mask" Stroke="White"StrokeThickness="13" StrokeDashArray="10 100"/>
    <!-- StrokeDashArray should be animated from "0 100" to "50 100"  -->

    <!-- The Blurry shadow of the line -->
    <Ellipse Name="blurry" Stroke="#FF7CA2CE" StrokeThickness="5">
        <Ellipse.Effect>
            <BlurEffect/>
        </Ellipse.Effect>
        <Ellipse.OpacityMask>
            <VisualBrush Visual="{Binding ElementName=Mask}"/>
        </Ellipse.OpacityMask>
    </Ellipse>

    <!-- The line itself -->
    <Ellipse Name="core" Stroke="Blue" StrokeThickness="1">
        <Ellipse.OpacityMask>
            <VisualBrush Visual="{Binding ElementName=Mask}"/>
        </Ellipse.OpacityMask>
    </Ellipse>
</UserControl>

So now I need to perform the animation over the first element in the StrokeDashArray and start it from code behind (C#) I can also let the animation soemewhere as a resource and start it from the code, or perform the whole animation in the code, I dont care, but please be specific about where to add the code for it.. I feel lost.

I also tried to add teh blurry and core lines to one grid and then apply the VisualBrush to it (so I apply it only one time, not two) but the effect is uglier since the blurry line is cut and is not softly ending like we want it to be hehehe

Sooo, Any help ?!?!?!?!?!

like image 589
javirs Avatar asked Dec 04 '22 11:12

javirs


2 Answers

Actually, you can animate the StrokeDashOffset instead of trying to animate the StrokeDashArray.

<Rectangle
   Width="70"
   Height="70"
   StrokeDashArray="2 0 0 2"
   StrokeThickness="2"
   Stroke="Black"
   Opacity="1"
   Fill="Transparent">
   <Rectangle.Triggers> 
            <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
                <BeginStoryboard> 
                    <Storyboard> 
                        <DoubleAnimation 
                           To="20" 
                           Duration="0:0:5" 
                           RepeatBehavior="Forever" 
                           By="2" 
                           Storyboard.TargetProperty="StrokeDashOffset" /> 
                    </Storyboard> 
                </BeginStoryboard> 
            </EventTrigger> 
        </Rectangle.Triggers> 
   </Rectangle>
like image 168
Trent T Avatar answered Jan 11 '23 02:01

Trent T


This is a bit of a tricky one as StrokeDashArray is a DoubleCollection so you cant really animate the values inside and have it reflect in the UI.

One option would be to animate a double property and create a new DoubleCollection that is bound to the StrokeDashArray.

Here is a working example:

Xaml:

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="211.75" Width="213" Name="UI">

    <Grid DataContext="{Binding ElementName=UI}">

        <Ellipse x:Name="lo" Stroke="White" StrokeThickness="13" StrokeDashArray="{Binding StrokeArray}" />

        <Ellipse Name="blurry" Stroke="#FF7CA2CE" StrokeThickness="5">
            <Ellipse.Effect>
                <BlurEffect/>
            </Ellipse.Effect>
            <Ellipse.OpacityMask>
                <VisualBrush Visual="{Binding ElementName=lo}"/>
            </Ellipse.OpacityMask>
        </Ellipse>

        <!-- The line itself -->
        <Ellipse Name="core" Stroke="Blue" StrokeThickness="1">
            <Ellipse.OpacityMask>
                <VisualBrush Visual="{Binding ElementName=lo}"/>
            </Ellipse.OpacityMask>
        </Ellipse>

        <Button Content="Start" HorizontalAlignment="Left" Height="49" Margin="29,65,0,0" VerticalAlignment="Top" Width="150" Click="Button_Click_1"/>

    </Grid>
</Window>

Code:

namespace WpfApplication21
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        public double StrokeValue
        {
            get { return (double)GetValue(StrokeValueProperty); }
            set { SetValue(StrokeValueProperty, value); }
        }

        public static readonly DependencyProperty StrokeValueProperty =
            DependencyProperty.Register("StrokeValue", typeof(double), typeof(MainWindow)
            , new PropertyMetadata(0.0, new PropertyChangedCallback(OnStrokeValueChanged)));

        private static void OnStrokeValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as MainWindow).StrokeArray = new DoubleCollection { (double)e.NewValue, 100 };
        }


        public DoubleCollection StrokeArray
        {
            get { return (DoubleCollection)GetValue(StrokeArrayProperty); }
            set { SetValue(StrokeArrayProperty, value); }
        }

        public static readonly DependencyProperty StrokeArrayProperty =
            DependencyProperty.Register("StrokeArray", typeof(DoubleCollection), typeof(MainWindow)
            , new PropertyMetadata(new DoubleCollection { 0, 100 }));


    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        var storyboard = new Storyboard();
        var animation = new DoubleAnimation(0,50,new Duration(TimeSpan.FromSeconds(5)));
        storyboard.Children.Add(animation);
        Storyboard.SetTarget(animation, this);
        Storyboard.SetTargetProperty(animation,new PropertyPath( MainWindow.StrokeValueProperty));
        storyboard.Begin();
    }

    }
}
like image 25
sa_ddam213 Avatar answered Jan 11 '23 04:01

sa_ddam213