This project is read-only.

Movement



MouseMove += (sender, args) =>
{
	var pt = args.GetPosition(null);
	pt.X -= (ball.Width/2);
	pt.Y -= (ball.Height/2);

	ball.SlideTo(pt.X, pt.Y, 1.2, AnimationTransitions.ElasticEaseOut, 0);
};


Particles



public MainPage()
{
    InitializeComponent();

    var rnd = new Random();
    MouseMove += (sender, args) =>
    {
        var pt = args.GetPosition(null);
        var particle = CreateParticle(pt.X, pt.Y);

        pt.X += rnd.NextDouble() * 100 * (rnd.NextDouble() < .5 ? 1 : -1);
        pt.Y += rnd.NextDouble() * 100 * (rnd.NextDouble() < .5 ? 1 : -1);

        particle.AutoAlphaTo(0, .5, AnimationTransitions.CubicEaseIn, 0);
        particle.SlideTo(pt.X, pt.Y, .5, AnimationTransitions.QuadraticEaseOut, 0).Complete += (eo, p) => LayoutRoot.Children.Remove(particle);
    };
}

public Ellipse CreateParticle ( double x, double y )
{
    var particle = new Ellipse { Width = 10, Height = 10, Fill = (Brush)Resources["BrushWhite"], Stroke = (Brush)Resources["BrushBlack"] };
    Canvas.SetLeft(particle, x);
    Canvas.SetTop(particle, y);
    LayoutRoot.Children.Add(particle);
    return particle;
}

Morphing



public const string PathAStr = "M473.608,465.611 C495.696,465.611 515.694,474.564 530.169,489.039 C544.644,503.515 553.598,523.512 553.598,545.601 C553.598,567.689 544.644,587.687 530.169,602.162 C515.694,616.638 495.696,625.591 473.608,625.591 C451.519,625.591 431.521,616.638 417.046,602.162 C402.571,587.687 393.618,567.689 393.618,545.601 C393.618,523.512 402.571,503.515 417.046,489.039 C431.521,474.564 451.519,465.611 473.608,465.611 z";
public const string PathBStr = "M473.608,465.61099 C474.07468,465.6105 529.74164,488.61145 530.16901,489.039 C530.40826,489.27838 553.67419,545.46271 553.59802,545.60101 C553.40863,545.94482 530.4082,601.77826 530.16901,602.16199 C529.84082,602.68854 473.74127,625.61157 473.608,625.591 C472.75119,625.45862 417.24103,602.27826 417.04599,602.16199 C416.62494,601.91107 393.90799,546.44482 393.61801,545.60101 C393.4043,544.97913 416.29425,488.5087 416.33517,488.48645 C416.37436,488.46515 473.24136,465.61139 473.608,465.61099 z";
public const string PathCStr = "M474.75772,463.46127 C475.2244,463.46078 555.42047,463.3027 555.84784,463.73026 C556.0871,463.96964 556.00323,545.45728 555.92706,545.59558 C555.73767,545.93939 555.58862,624.91663 555.34943,625.30035 C555.02124,625.8269 473.74127,625.61157 473.608,625.591 C472.75119,625.45862 393.43631,625.89453 393.24127,625.77826 C392.82022,625.52734 393.40799,546.44482 393.11801,545.60101 C392.9043,544.97913 393.19995,463.80078 393.24088,463.77853 C393.28006,463.75723 474.39108,463.46167 474.75772,463.46127 z";
public const string PathDStr = "M474.75772,463.46127 C475.2244,463.46078 474.72626,463.3027 475.15363,463.73026 C475.39288,463.96964 556.00323,545.45728 555.92706,545.59558 C555.73767,545.93939 555.58862,624.91663 555.34943,625.30035 C555.02124,625.8269 473.74127,625.61157 473.608,625.591 C472.75119,625.45862 393.43631,625.89453 393.24127,625.77826 C392.82022,625.52734 393.40799,546.44482 393.11801,545.60101 C392.9043,544.97913 474.18613,463.80078 474.22705,463.77853 C474.26624,463.75723 474.39108,463.46167 474.75772,463.46127 z";
        
public MainPage()
{
    InitializeComponent();

    // INIT
    pathA.Data = PathUtils.ParsePathGeometryString(PathAStr);
    pathB.Data = PathUtils.ParsePathGeometryString(PathBStr);
    pathC.Data = PathUtils.ParsePathGeometryString(PathCStr);
    pathD.Data = PathUtils.ParsePathGeometryString(PathDStr);

    // ENTER
    pathA.MouseEnter += (s, args) => SetPaths(PathAStr);
    pathB.MouseEnter += (s, args) => SetPaths(PathBStr);
    pathC.MouseEnter += (s, args) => SetPaths(PathCStr);
    pathD.MouseEnter += (s, args) => SetPaths(PathDStr);

    // LEAVE
    pathA.MouseLeave += (s, args) => SetPaths(null);
    pathB.MouseLeave += (s, args) => SetPaths(null);
    pathB.MouseLeave += (s, args) => SetPaths(null);
    pathD.MouseLeave += (s, args) => SetPaths(null);
}

public void SetPaths ( string newPath )
{
    ArtefactAnimator.AddEase(pathA, Path.DataProperty, PathUtils.ParsePathGeometryString(newPath ?? PathAStr), .5, AnimationTransitions.ElasticEaseOut, 0);
    ArtefactAnimator.AddEase(pathB, Path.DataProperty, PathUtils.ParsePathGeometryString(newPath ?? PathBStr), .5, AnimationTransitions.ElasticEaseOut, 0);
    ArtefactAnimator.AddEase(pathC, Path.DataProperty, PathUtils.ParsePathGeometryString(newPath ?? PathCStr), .5, AnimationTransitions.ElasticEaseOut, 0);
    ArtefactAnimator.AddEase(pathD, Path.DataProperty, PathUtils.ParsePathGeometryString(newPath ?? PathDStr), .5, AnimationTransitions.ElasticEaseOut, 0);
}

Color



Random rnd = new Random();

public MainPage()
{
    InitializeComponent();

    LayoutRoot.MouseEnter += (sender, args) => RandomizeColor();
    LayoutRoot.MouseLeave += (sender, args) => ArtefactAnimator.AddEase(LayoutRoot,
                                                                        Canvas.BackgroundProperty, (SolidColorBrush)Resources["BrushBlack"], 
                                                                        1, AnimationTransitions.CubicEaseOut, 0);
}
         
private void RandomizeColor ()
{
    ArtefactAnimator.AddEase(LayoutRoot,
    Canvas.BackgroundProperty, new SolidColorBrush(new Color { A = 255, B = (byte)rnd.Next(0, 255), G = (byte)rnd.Next(0, 255), R = (byte)rnd.Next(0, 255) }),
    1, AnimationTransitions.CubicEaseOut, 0).Complete += (eo, p) => RandomizeColor();
}

Transforms



CompositeTransform

Random rnd = new Random();

public MainPage()
{
    InitializeComponent();

    // ENTER
    pathA.MouseEnter += (s, args) => Scale();
    pathB.MouseEnter += (s, args) => Skew();
    pathC.MouseEnter += (s, args) => Translate();
    pathD.MouseEnter += (s, args) => Rotate();

    // LEAVE
    pathA.MouseLeave += (s, args) => Reset(pathA);
    pathB.MouseLeave += (s, args) => Reset(pathB);
    pathC.MouseLeave += (s, args) => Reset(pathC);
    pathD.MouseLeave += (s, args) => Reset(pathD);

    // CENTER TRANSFORMS
    pathA.RenderTransformOrigin = new Point(.5,.5);
    pathB.RenderTransformOrigin = new Point(.5,.5);
    pathC.RenderTransformOrigin = new Point(.5,.5);
    pathD.RenderTransformOrigin = new Point(.5,.5);
}

// TRANSFORMS

private void Scale()
{
    var scale = rnd.Next(80, 200)/100D;
    ArtefactAnimator.AddEase(pathA, RenderTransformProperty, new CompositeTransform { ScaleX = scale, ScaleY = scale}, .5, AnimationTransitions.ElasticEaseOut, 0).Complete += (eo,p)=> Scale();
}

private void Skew()
{
    ArtefactAnimator.AddEase(pathB, RenderTransformProperty, new CompositeTransform { SkewX = rnd.Next(-50, 50), SkewY = rnd.Next(-50, 50) }, .5, AnimationTransitions.CircleEaseOut, 0).Complete += (eo, p) => Skew();
}

private void Translate()
{
    ArtefactAnimator.AddEase(pathC, RenderTransformProperty, new CompositeTransform { TranslateX = rnd.Next(-20, 20), TranslateY = rnd.Next(-20, 20) }, .5, AnimationTransitions.BounceEaseOut, 0).Complete += (eo, p) => Translate();
}

private void Rotate()
{
    ArtefactAnimator.AddEase(pathD, RenderTransformProperty, new CompositeTransform { Rotation = rnd.Next(0, 360)}, .5, AnimationTransitions.ElasticEaseOut, 0).Complete += (eo, p) => Rotate();
}

// RESET

private static void Reset(Path path)
{
    ArtefactAnimator.AddEase(path, RenderTransformProperty, new CompositeTransform(), .5, AnimationTransitions.ElasticEaseOut, 0);
}





RenderTransform

Random rnd = new Random();
public MainPage()
{
    InitializeComponent();

    // ENTER
    pathA.MouseEnter += (s, args) => Scale();
    pathB.MouseEnter += (s, args) => Skew();
    pathC.MouseEnter += (s, args) => Translate();
    pathD.MouseEnter += (s, args) => Rotate();

    // LEAVE
    pathA.MouseLeave += (s, args) => ArtefactAnimator.StopEase( pathA.GetNormalizedTransform<ScaleTransform>() );
    pathB.MouseLeave += (s, args) => ArtefactAnimator.StopEase( pathB.GetNormalizedTransform<SkewTransform>() );
    pathC.MouseLeave += (s, args) => ArtefactAnimator.StopEase( pathC.GetNormalizedTransform<TranslateTransform>() );
    pathD.MouseLeave += (s, args) => ArtefactAnimator.StopEase( pathD.GetNormalizedTransform<RotateTransform>() );

    // INIT TRANSFORMS
    pathA.NormalizeTransformGroup();
    pathB.NormalizeTransformGroup();
    pathC.NormalizeTransformGroup();
    pathD.NormalizeTransformGroup();
			
    // CENTER TRANSFORMS
    pathA.RenderTransformOrigin = new Point(.5,.5);
    pathB.RenderTransformOrigin = new Point(.5,.5);
    pathC.RenderTransformOrigin = new Point(.5,.5);
    pathD.RenderTransformOrigin = new Point(.5,.5);
}

// TRANSFORMS

private void Scale()
{
    var scale = rnd.Next(80, 200)/100D;
    pathA.ScaleTo(scale, scale, .5, AnimationTransitions.ElasticEaseOut, 0).Complete += (eo,p)=> Scale();
}

private void Skew()
{
    pathB.SkewTo(rnd.Next(-50, 50), rnd.Next(-50, 50), .5, AnimationTransitions.CircleEaseOut, 0).Complete += (eo, p) => Skew();
}

private void Translate()
{
    pathC.OffsetTo(rnd.Next(-20, 20), rnd.Next(-20, 20), .5, AnimationTransitions.BounceEaseOut, 0).Complete += (eo, p) => Translate();
}

private void Rotate()
{
    pathD.RotateTo(rnd.Next(0, 360), 1.5, AnimationTransitions.ElasticEaseOut, 0).Complete += (eo, p) => Rotate();
}

Effects



Random rnd = new Random();

public MainPage()
{
    InitializeComponent();

    // SHADOW
    shapeA.Effect = new BlurEffect { Radius = 0 };
    shapeA.MouseEnter += (s, args) => UpdateBlur(true);
    shapeA.MouseLeave += (s, args) => UpdateBlur(false);

    // BLUR
    shapeB.Effect = new DropShadowEffect { Color = Colors.Gray }; 
    shapeB.MouseEnter += (s, args) => UpdateShadow(true);
    shapeB.MouseLeave += (s, args) => UpdateShadow(false);
}

// BLUR
private void UpdateBlur(bool isTrue)
{
    var blur = new BlurEffect
    {
        Radius = !isTrue ? 0 : rnd.Next(0, 20)
    };

    ArtefactAnimator.AddEase(shapeA, EffectProperty, blur, 1, AnimationTransitions.CubicEaseOut, 0).Complete += (eo, p) => UpdateBlur(isTrue);
}

// SHADOW
private void UpdateShadow(bool isTrue)
{
    var shadow = new DropShadowEffect
    {
        ShadowDepth = !isTrue ? 0 : rnd.Next(6,20),
        BlurRadius= !isTrue ? 0 : rnd.Next(0,20),
        Direction= !isTrue ? 0 : rnd.Next(0,360),
        Opacity = !isTrue ? 0 : (rnd.NextDouble() * .5)+.5,
        Color = ((DropShadowEffect)shapeB.Effect).Color
    };

    ArtefactAnimator.AddEase(shapeB, EffectProperty, shadow, 1, AnimationTransitions.CubicEaseOut, 0).Complete += (eo, p) => UpdateShadow(isTrue);
}

Lists



<UserControl.Resources>

    <!-- ADDS SMOOTH SCROLL -->
    <ItemsPanelTemplate x:Key="ItemsPanelTemplate">
        <StackPanel/>
    </ItemsPanelTemplate>
  
</UserControl.Resources>

<ListBox x:Name="lb" Height="247" Width="100" ItemsPanel="{StaticResource ItemsPanelTemplate}" />


private static ScrollViewer _scrollViewer;

public MainPage()
{
    InitializeComponent();
    Loaded += MainPage_Loaded;
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    // INIT
    lb.Items.Clear();
    lb.UpdateLayout();

    // SCROLL INTERACTION
    _scrollViewer = FindVisualChild<ScrollViewer>(lb);
    var bar = FindVisualChild<ScrollBar>(_scrollViewer);
    if ( bar != null ) bar.ValueChanged += (s, args) => SetValue(ListBoxScrollOffsetProperty, args.NewValue);

    // INPUT
    addBtn.Click += (s, args) => AddItem();
}

private void AddItem()
{
    // Create New ListBoxItem
    var lbi = new ListBoxItem
    {
        Content = "Item " + lb.Items.Count,
        RenderTransform = new CompositeTransform { TranslateX = -lb.Width },
    };

    // Add ListBoxItem
    lb.Items.Add(lbi);
    lb.UpdateLayout();
            
    // Animate In Item
    ArtefactAnimator.AddEase(lbi.RenderTransform, CompositeTransform.TranslateXProperty, 0, 1, AnimationTransitions.CubicEaseOut, 0);
    ArtefactAnimator.AddEase(this, ListBoxScrollOffsetProperty, _scrollViewer.ScrollableHeight, .8, AnimationTransitions.CubicEaseOut, 0);
}


// LISTBOX SCROLL OFFSET
    public static readonly DependencyProperty ListBoxScrollOffsetProperty =
    DependencyProperty.Register("ListBoxScrollOffset", typeof(double), typeof(MainPage), new PropertyMetadata(0.0, OnListBoxScrollOffsetChanged));

private static void OnListBoxScrollOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    _scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
}

public double ListBoxScrollOffset
{
    get { return (double)GetValue(ListBoxScrollOffsetProperty); }
    set { SetValue(ListBoxScrollOffsetProperty, value); }
}

// VISUAL HELPER
public static childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
    for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        var child = VisualTreeHelper.GetChild(obj, i);
        if (child != null && child is childItem)
        {
            return (childItem)child;
        }
        else
        {
            var childOfChild = FindVisualChild<childItem>(child);
            if (childOfChild != null)
            {
                return childOfChild;
            }
        }
    }
    return null;
}


Data Bound Lists



<UserControl.Resources>

    <SolidColorBrush x:Key="BrushBlack" Color="#FF1A1A1A"/>
    <SolidColorBrush x:Key="BrushWhite" Color="#FFF4F4F5"/>

    <SampleData:SampleDataSource x:Key="SampleDataSource" d:IsDataSource="True"/>
        
    <DataTemplate x:Key="ItemTemplate">
        <StackPanel>
            <Grid x:Name="background" Background="{StaticResource BrushWhite}">
                <TextBlock Text="{Binding Title}" />
            </Grid>
        </StackPanel>
    </DataTemplate>

</UserControl.Resources>

<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource} }"  >
    <ListBox x:Name="lb" 
        Height="247" 
        Width="100"          
        ItemTemplate="{StaticResource ItemTemplate}" 
        ItemsSource="{Binding Collection}">
    </ListBox>
</Grid>


private static bool _isFiltered;
private static readonly Random Rnd = new Random();

public MainPage()
{
    InitializeComponent();
    filterBtn.Click += (s, args) => FilterToggle();
}

private void FilterToggle()
{
    _isFiltered = !_isFiltered;

    if ( _isFiltered )
    {
        filterBtn.Content = "Clear";
        for (var i = 0; i < lb.Items.Count; i++ )
        {
            SetMode((ListBoxItem)lb.ItemContainerGenerator.ContainerFromIndex(i), Rnd.NextDouble() < .5);
        }
    }
    else
    {
        filterBtn.Content = "Filter";
        for (var i = 0; i < lb.Items.Count; i++)
        {
            SetMode((ListBoxItem)lb.ItemContainerGenerator.ContainerFromIndex(i), false);
        }
    }
}

// ANIMATE ITEM TEMPLATE BACKGROUND
private void SetMode(ListBoxItem lbi, bool isFiltered)
{
    if (lbi == null) return;
    var bg = (Grid)FindVisualChildByName(lbi, "background");

    ArtefactAnimator.AddEase(bg, Panel.BackgroundProperty, 
            isFiltered ? Resources["BrushBlack"] : Resources["BrushWhite"], 
            .8, AnimationTransitions.CubicEaseOut, 0);
}

// VISUAL HELPER
public static DependencyObject FindVisualChildByName(DependencyObject obj, string name)
{
    for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        var child = VisualTreeHelper.GetChild(obj, i) as FrameworkElement;
        if (child != null && child.Name == name)
        {
            return child;
        }
        else
        {
            var childOfChild = FindVisualChildByName(child, name);
            if (childOfChild != null)
            {
                return childOfChild;
            }
        }
    }
    return null;
}

Last edited Jan 14, 2014 at 6:52 AM by jgraup, version 23

Comments

LeifN Nov 22, 2010 at 2:41 PM 
Thanks, - you saved me from a lot of storyboard-frustrations!

MilesLukas Sep 17, 2010 at 12:31 AM 
Great examples. Great utility. I also used it to tween the 3D plane property not included in the examples:

C#
ArtefactAnimator.AddEase(canv, ProjectionProperty, new PlaneProjection { RotationX = 360 }, .5, AnimationTransitions.CubicEaseInOut, 0);

jgraup May 17, 2010 at 12:58 AM 
@saandesh - You can animate the items in a RenderTransformGroup. First normalize an element's RenderTransform to make sure all the necessary transforms are in place.

element.NormalizeTransformGroup();

Then you can use extensions to target specific transforms:

ScaleTo, SkewTo, OffsetTo, & RotateTo

If you want to directly access each Transform in the group, use:

element.GetNormalizedTransform<ScaleTransform>( );

saandesh May 11, 2010 at 3:21 PM 
I am using Silverlight 3 and I found that CompositeTransform is not present there....Please tell me any similar class I can use

thank you
sandesh daddi
sanshark.com

worldlifesite May 7, 2010 at 9:35 AM 
Thank you, I'll use animation more in my projects.