using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using HandyControl.Data;
namespace HandyControl.Controls
{
public class AnimationPath : Shape
{
private bool _isLoaded;
///
/// 故事版
///
private Storyboard _storyboard;
///
/// 路径
///
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data),
typeof(Geometry), typeof(AnimationPath), new FrameworkPropertyMetadata(null,
OnPropertiesChanged));
private static void OnPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is AnimationPath path)
{
path.UpdatePath();
}
}
///
/// 路径
///
public Geometry Data
{
get => (Geometry)GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
protected override Geometry DefiningGeometry => Data ?? Geometry.Empty;
///
/// 路径长度
///
public static readonly DependencyProperty PathLengthProperty = DependencyProperty.Register(
"PathLength", typeof(double), typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
OnPropertiesChanged));
///
/// 路径长度
///
public double PathLength
{
get => (double)GetValue(PathLengthProperty);
set => SetValue(PathLengthProperty, value);
}
///
/// 动画间隔时间
///
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(
"Duration", typeof(Duration), typeof(AnimationPath), new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(2)),
OnPropertiesChanged));
///
/// 动画间隔时间
///
public Duration Duration
{
get => (Duration)GetValue(DurationProperty);
set => SetValue(DurationProperty, value);
}
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
"IsPlaying", typeof(bool), typeof(AnimationPath), new FrameworkPropertyMetadata(true, (o, args) =>
{
var ctl = (AnimationPath)o;
var v = (bool)args.NewValue;
if (v)
{
ctl.UpdatePath();
}
else
{
ctl._storyboard?.Pause();
}
}));
///
/// 是否正在播放动画
///
public bool IsPlaying
{
get => (bool)GetValue(IsPlayingProperty);
set => SetValue(IsPlayingProperty, value);
}
public static readonly DependencyProperty RepeatBehaviorProperty = DependencyProperty.Register(
"RepeatBehavior", typeof(RepeatBehavior), typeof(AnimationPath), new PropertyMetadata(RepeatBehavior.Forever));
///
/// 动画重复行为
///
public RepeatBehavior RepeatBehavior
{
get => (RepeatBehavior)GetValue(RepeatBehaviorProperty);
set => SetValue(RepeatBehaviorProperty, value);
}
static AnimationPath()
{
StretchProperty.AddOwner(typeof(AnimationPath), new FrameworkPropertyMetadata(Stretch.Uniform,
OnPropertiesChanged));
StrokeThicknessProperty.AddOwner(typeof(AnimationPath), new FrameworkPropertyMetadata(1.0,
OnPropertiesChanged));
}
public AnimationPath()
{
Loaded += (s, e) =>
{
if (_isLoaded) return;
UpdatePath();
_isLoaded = true;
};
}
///
/// 动画完成事件
///
public static readonly RoutedEvent CompletedEvent =
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
typeof(EventHandler), typeof(AnimationPath));
///
/// 动画完成事件
///
public event EventHandler Completed
{
add => AddHandler(CompletedEvent, value);
remove => RemoveHandler(CompletedEvent, value);
}
private void UpdatePath()
{
if (!Duration.HasTimeSpan || !IsPlaying) return;
StrokeDashOffset = PathLength;
StrokeDashArray = new DoubleCollection(new List
{
PathLength,
PathLength
});
//定义动画
_storyboard = new Storyboard
{
RepeatBehavior = RepeatBehavior
};
_storyboard.Completed += (s, e) => RaiseEvent(new RoutedEventArgs(CompletedEvent));
var frames = new DoubleAnimationUsingKeyFrames();
//开始位置
var frame0 = new LinearDoubleKeyFrame
{
Value = PathLength,
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
};
//结束位置
var frame1 = new LinearDoubleKeyFrame
{
Value = -PathLength,
KeyTime = KeyTime.FromTimeSpan(Duration.TimeSpan)
};
frames.KeyFrames.Add(frame0);
frames.KeyFrames.Add(frame1);
Storyboard.SetTarget(frames, this);
Storyboard.SetTargetProperty(frames, new PropertyPath(StrokeDashOffsetProperty));
_storyboard.Children.Add(frames);
_storyboard.Begin();
}
}
}