【问题标题】:How do you animate a line on a canvas in C#?如何在 C# 中为画布上的线条制作动画?
【发布时间】:2013-03-06 08:15:51
【问题描述】:

如何在屏幕上画一条线?

我正在尝试为 C#/WPF 项目中画布上的线条制作动画。

我想使用 C# 代码而不是 XAML。

【问题讨论】:

    标签: c# wpf animation canvas


    【解决方案1】:

    我有一个正在运行的示例,它使用 MVVM 模式并在 ListBox 中创建行,其中 Canvas 作为其 ItemsPanel

    我实际上是为this question 制作的,但 OP 有点消失了,从未就此联系过我。

    这是我电脑里的样子:

    它的主要部分是这样的:

    <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>
    

    视图模型:

    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
    }
    

    编辑:源代码现在在GitHub

    【讨论】:

    【解决方案2】:

    您将需要使用Storyboard 并为Line.X2Line.Y2 属性设置动画。看看这是否适合你。

    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>
    

    按钮点击事件

    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);
    }
    

    【讨论】:

    • 我认为最好从 Line 类扩展以公开 AngleRadius 属性和动画,而不是单独为 X2Y2 属性设置动画离开那个。
    • @JeffMercado 你是对的,这只是给 OP 一个方向的简单示例。
    • 谢谢!这是简短而甜蜜的。正是我需要的。我欠你的债。
    猜你喜欢
    • 2014-07-19
    • 2019-11-11
    • 1970-01-01
    • 2018-12-14
    • 2014-10-18
    • 1970-01-01
    • 2014-06-29
    • 2020-05-25
    • 2016-05-23
    相关资源
    最近更新 更多