Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you animate a line on a canvas in C#?

How would you make a line slowly draw across the screen?

I am trying to animate a line on a canvas in a C#/WPF project.

I would like to use C# code and not XAML.

like image 282
UnskilledBuild Avatar asked Mar 18 '13 03:03

UnskilledBuild


People also ask

Can you animate on canvas?

You can create animations with HTML5 by combining HTML, CSS, and JavaScript (JS), with which you can build shapes.

What is HTML5 animations?

Animate enables you to create an HTML5 Canvas document with rich artwork, graphics, animations, and so on. A new document type (HTML5 Canvas) has been added to Animate that provides native support for creating rich and interactive HTML5 content.


2 Answers

I Have a running sample that uses the MVVM Pattern and creates Lines within a ListBox that has a Canvas as its ItemsPanel.

I actually made it for this question, but the OP kind of dissapeared and never contacted me about it.

This is what it looks like in my computer:

enter image description here

The main part of it is this:

<ListBox ItemsSource="{Binding}" x:Name="lst" Height="500" Width="500">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="FocusVisualStyle">
                <Setter.Value>
                    <Style TargetType="Control">
                        <Setter Property="Opacity" Value="0"/>
                    </Style>
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Line X1="{Binding X1}" Y1="{Binding Y1}"
                              X2="{Binding X2}" Y2="{Binding Y2}" 
                              StrokeThickness="{Binding Thickness}"
                              Opacity="{Binding Opacity}"
                              x:Name="Line">
                            <Line.Stroke>
                                <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                                    <GradientStop Color="{Binding Color1}" Offset="0"/>
                                    <GradientStop Color="{Binding Color2}" Offset="1"/>
                                </LinearGradientBrush>
                            </Line.Stroke>
                        </Line>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter Property="Effect" TargetName="Line">
                                    <Setter.Value>
                                        <DropShadowEffect Color="CornflowerBlue" ShadowDepth="3" BlurRadius="10"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

ViewModel:

public class LineViewModel : INotifyPropertyChanged
{
    #region Timer-based Animation

    private System.Threading.Timer Timer;
    private static Random Rnd = new Random();

    private bool _animate;
    public bool Animate
    {
        get { return _animate; }
        set
        {
            _animate = value;
            NotifyPropertyChanged("Animate");
            if (value)
                StartTimer();
            else
                StopTimer();
        }
    }

    private int _animationSpeed = 1;
    public int AnimationSpeed
    {
        get { return _animationSpeed; }
        set
        {
            _animationSpeed = value;
            NotifyPropertyChanged("AnimationSpeed");
            if (Timer != null)
                Timer.Change(0, 100/value);
        }
    }

    private static readonly List<int> _animationSpeeds = new List<int>{1,2,3,4,5};
    public List<int> AnimationSpeeds
    {
        get { return _animationSpeeds; }
    }

    public void StartTimer()
    {
        StopTimer();
        Timer = new Timer(x => Timer_Tick(), null, 0, 100/AnimationSpeed);
    }

    public void StopTimer()
    {
        if (Timer != null)
        {
            Timer.Dispose();
            Timer = null;
        }
    }

    private void Timer_Tick()
    {
        X1 = X1 + Rnd.Next(-2, 3);
        Y1 = Y1 + Rnd.Next(-2, 3);
        X2 = X2 + Rnd.Next(-2, 3);
        Y2 = Y2 + Rnd.Next(-2, 3);
    }

    #endregion

    #region Coordinates

    private double _x1;
    public double X1
    {
        get { return _x1; }
        set
        {
            _x1 = value;
            NotifyPropertyChanged("X1");
        }
    }

    private double _y1;
    public double Y1
    {
        get { return _y1; }
        set
        {
            _y1 = value;
            NotifyPropertyChanged("Y1");
        }
    }

    private double _x2;
    public double X2
    {
        get { return _x2; }
        set
        {
            _x2 = value;
            NotifyPropertyChanged("X2");
        }
    }

    private double _y2;
    public double Y2
    {
        get { return _y2; }
        set
        {
            _y2 = value;
            NotifyPropertyChanged("Y2");
        }
    }

    #endregion

    #region Other Properties

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            NotifyPropertyChanged("Name");
        }
    }

    private double _thickness;
    public double Thickness
    {
        get { return _thickness; }
        set
        {
            _thickness = value;
            NotifyPropertyChanged("Thickness");
        }
    }

    public Color Color1 { get; set; }
    public Color Color2 { get; set; }

    private double _opacity = 1;
    public double Opacity
    {
        get { return _opacity; }
        set
        {
            _opacity = value;
            NotifyPropertyChanged("Opacity");
        }
    }

    #endregion

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string propertyName)
    {
        Application.Current.Dispatcher.BeginInvoke((Action)(() =>
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }));
    }

    #endregion
}

Edit: Source code now on GitHub

like image 185
Federico Berasategui Avatar answered Oct 14 '22 18:10

Federico Berasategui


You will need to use a Storyboard and animate the Line.X2 and Line.Y2 Properties. See if this works for you.

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Canvas Name="myCanvas">
        <Button Canvas.Left="248" Canvas.Top="222" Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
    </Canvas>
</Window>

Button Click Event

private void button1_Click(object sender, RoutedEventArgs e)
{
    Line line = new Line();
    myCanvas.Children.Add(line);
    line.Stroke = Brushes.Red;
    line.StrokeThickness = 2;
    line.X1 = 0;
    line.Y1 = 0;

    Storyboard sb = new Storyboard();
    DoubleAnimation da = new DoubleAnimation(line.Y2 , 100, new Duration(new TimeSpan(0, 0, 1)));
    DoubleAnimation da1 = new DoubleAnimation(line.X2, 100, new Duration(new TimeSpan(0, 0, 1)));
    Storyboard.SetTargetProperty(da, new PropertyPath("(Line.Y2)"));
    Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X2)"));
    sb.Children.Add(da);
    sb.Children.Add(da1);

    line.BeginStoryboard(sb);
}
like image 29
Mark Hall Avatar answered Oct 14 '22 17:10

Mark Hall