using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace AIStudio.Wpf.DiagramDesigner { /// /// LineControl.xaml 的交互逻辑 /// public partial class LineControl : UserControl { public LineControl() { InitializeComponent(); this.Loaded += PathAnimation_Loaded; this.Unloaded += LineControl_Unloaded; } private void LineControl_Unloaded(object sender, RoutedEventArgs e) { if (this.DataContext is ConnectionViewModel connector && connector.AnimationViewModel != null) { connector.AnimationViewModel.PropertyChanged -= Connector_PropertyChanged; } _story?.Stop(); } private async void PathAnimation_Loaded(object sender, RoutedEventArgs e) { if (this.DataContext is ConnectionViewModel connector && connector.AnimationViewModel != null) { connector.AnimationViewModel.PropertyChanged -= Connector_PropertyChanged; connector.AnimationViewModel.PropertyChanged += Connector_PropertyChanged; } this.ball.Visibility = Visibility.Collapsed; await DoAnimation(); } private async void Connector_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { switch (e.PropertyName) { case nameof(AnimationViewModel.Animation): case nameof(AnimationViewModel.Duration): await DoAnimation(); break; case nameof(AnimationViewModel.Start): await Application.Current.Dispatcher.Invoke(async () => { await DoAnimation(); }); break; } } private async Task DoAnimation() { if (this.DataContext is ConnectionViewModel connector && connector.IsFullConnection) { if (connector.AnimationViewModel.Repeat == false) { if (connector.AnimationViewModel.Start == false || connector.AnimationViewModel.Completed == 1) { return; } connector.AnimationViewModel.Completed = 1; connector.AnimationViewModel.Start = false; } await System.Threading.Tasks.Task.Delay(10); switch (connector.AnimationViewModel.Animation) { case LineAnimation.None: _story?.Stop(this); ball.Visibility = Visibility.Collapsed; break; case LineAnimation.PathAnimation: if (connector.ColorViewModel.FillColor.BrushType == BrushType.SolidColorBrush && connector.ColorViewModel.FillColor.Color == Colors.White) { connector.ColorViewModel.FillColor.Color = Colors.Red; } PathAnimation(connector.AnimationViewModel); break; case LineAnimation.DashAnimation: if (connector.ColorViewModel.LineDashStyle == LineDashStyle.None) { connector.ColorViewModel.LineDashStyle = LineDashStyle.Dash1; } DashAnimation(connector.AnimationViewModel); break; } } } Storyboard _story; private void PathAnimation(IAnimationViewModel animationViewModel) { this.ball.Visibility = Visibility.Visible; Canvas.SetTop(this.ball, -this.ball.ActualHeight / 2); Canvas.SetLeft(this.ball, -this.ball.ActualWidth / 2); this.ball.RenderTransformOrigin = new Point(0.5, 0.5); TranslateTransform translate = new TranslateTransform(); RotateTransform rotate = new RotateTransform(); TransformGroup group = new TransformGroup(); group.Children.Add(rotate);//先旋转 group.Children.Add(translate);//再平移 this.ball.RenderTransform = group; NameScope.SetNameScope(this, new NameScope()); this.RegisterName("translate", translate); this.RegisterName("rotate", rotate); DoubleAnimationUsingPath animationX = new DoubleAnimationUsingPath(); animationX.PathGeometry = this.line.Data?.GetFlattenedPathGeometry(); animationX.Source = PathAnimationSource.X; animationX.Duration = new Duration(TimeSpan.FromSeconds(animationViewModel.Duration)); DoubleAnimationUsingPath animationY = new DoubleAnimationUsingPath(); animationY.PathGeometry = this.line.Data?.GetFlattenedPathGeometry(); animationY.Source = PathAnimationSource.Y; animationY.Duration = animationX.Duration; DoubleAnimationUsingPath animationAngle = new DoubleAnimationUsingPath(); animationAngle.PathGeometry = this.line.Data?.GetFlattenedPathGeometry(); animationAngle.Source = PathAnimationSource.Angle; animationAngle.Duration = animationX.Duration; _story?.Stop(this); _story = new Storyboard(); //_story.RepeatBehavior = RepeatBehavior.Forever; //story.AutoReverse = true; _story.Children.Add(animationX); _story.Children.Add(animationY); _story.Children.Add(animationAngle); _story.Completed += (s, d) => { if (animationViewModel.Repeat) { _story.Begin(this, true); } else { this.ball.Visibility = Visibility.Collapsed; animationViewModel.Completed = 100; } }; Storyboard.SetTargetName(animationX, "translate"); Storyboard.SetTargetName(animationY, "translate"); Storyboard.SetTargetName(animationAngle, "rotate"); Storyboard.SetTargetProperty(animationX, new PropertyPath(TranslateTransform.XProperty)); Storyboard.SetTargetProperty(animationY, new PropertyPath(TranslateTransform.YProperty)); Storyboard.SetTargetProperty(animationAngle, new PropertyPath(RotateTransform.AngleProperty)); _story.Begin(this, true); } private void DashAnimation(IAnimationViewModel animationViewModel) { this.ball.Visibility = Visibility.Collapsed; var animation = new DoubleAnimation(0, -10, new Duration(TimeSpan.FromSeconds(animationViewModel.Duration))) { RepeatBehavior = RepeatBehavior.Forever, }; Storyboard.SetTargetProperty(animation, new PropertyPath("StrokeDashOffset")); Storyboard.SetTarget(animation, this.line); _story?.Stop(this); _story = new Storyboard(); _story.RepeatBehavior = RepeatBehavior.Forever; _story.Children.Add(animation); _story.Completed += (s, d) => { if (animationViewModel.Repeat) { _story.Begin(this, true); } else { this.ball.Visibility = Visibility.Collapsed; animationViewModel.Completed = 100; } }; _story.Begin(this, true); } } }