wpf 如何在 C# 中为画布上的线条设置动画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15469283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:07:55  来源:igfitidea点击:

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

c#wpfanimationcanvas

提问by UnskilledBuild

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.

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

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

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

回答by Federico Berasategui

I Have a running sample that uses the MVVM Pattern and creates Lines within a ListBoxthat has a Canvasas its ItemsPanel.

我有一个正在运行的样品使用MVVM模式和内创建一个行ListBox具有CanvasItemsPanel

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

我实际上是为这个问题做的,但是 OP 有点消失了,而且从未就此事与我联系过。

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

编辑:现在在GitHub 上的源代码

回答by Mark Hall

You will need to use a Storyboardand animate the Line.X2and Line.Y2Properties. See if this works for you.

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

MainWindow.xaml

主窗口.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);
}