diff --git a/AIStudio.Wpf.DiagramApp/Views/PropertyControl.xaml b/AIStudio.Wpf.DiagramApp/Views/PropertyControl.xaml index 97ff0d5..82923bb 100644 --- a/AIStudio.Wpf.DiagramApp/Views/PropertyControl.xaml +++ b/AIStudio.Wpf.DiagramApp/Views/PropertyControl.xaml @@ -298,6 +298,23 @@ + diff --git a/AIStudio.Wpf.DiagramDesigner/Enums/LineAnimation.cs b/AIStudio.Wpf.DiagramDesigner/Enums/LineAnimation.cs new file mode 100644 index 0000000..d985ed4 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/Enums/LineAnimation.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace AIStudio.Wpf.DiagramDesigner +{ + public enum LineAnimation + { + [Description("无")] + None, + [Description("路径动画")] + PathAnimation, + [Description("虚线流动")] + DashAnimation, + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/UserControls/DiagramControl.xaml b/AIStudio.Wpf.DiagramDesigner/UserControls/DiagramControl.xaml index 8047cc7..53ae2a5 100644 --- a/AIStudio.Wpf.DiagramDesigner/UserControls/DiagramControl.xaml +++ b/AIStudio.Wpf.DiagramDesigner/UserControls/DiagramControl.xaml @@ -514,7 +514,11 @@ - + + + + + @@ -523,23 +527,21 @@ - + + - - - - - + - - --> + + @@ -554,24 +558,26 @@ - - - + + - - + + + + @@ -637,25 +643,12 @@ - - - - - - - - + Value="Black" />--> + diff --git a/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml b/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml new file mode 100644 index 0000000..e0d6ce3 --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml.cs b/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml.cs new file mode 100644 index 0000000..e65141c --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/UserControls/LineControl.xaml.cs @@ -0,0 +1,177 @@ +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 static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( + nameof(IsSelected), typeof(bool), typeof(LineControl), new FrameworkPropertyMetadata( + false, OnIsSelectedChanged)); + + private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (object.Equals(e.NewValue, true)) + { + (d as LineControl).line.Stroke = Brushes.Black; + } + } + + public bool IsSelected + { + get => (bool)GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + public LineControl() + { + InitializeComponent(); + + this.Loaded += PathAnimation_Loaded; + this.Unloaded += LineControl_Unloaded; + } + + private void LineControl_Unloaded(object sender, RoutedEventArgs e) + { + if (this.DataContext is ConnectorViewModel connector) + { + connector.PropertyChanged -= Connector_PropertyChanged; + } + _story?.Stop(); + } + + private async void PathAnimation_Loaded(object sender, RoutedEventArgs e) + { + if (this.DataContext is ConnectorViewModel connector) + { + connector.PropertyChanged -= Connector_PropertyChanged; + connector.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(ConnectorViewModel.LineAnimation): + case nameof(ConnectorViewModel.PathGeneratorResult): + await DoAnimation(); + break; + + } + } + + private async Task DoAnimation() + { + if (this.DataContext is ConnectorViewModel connector && connector.IsFullConnection) + { + await System.Threading.Tasks.Task.Delay(100); + switch (connector.LineAnimation) + { + case LineAnimation.None: + _story?.Stop(); + ball.Visibility = Visibility.Collapsed; + break; + case LineAnimation.PathAnimation: + PathAnimation(); + break; + case LineAnimation.DashAnimation: + DashAnimation(); + break; + } + } + } + + Storyboard _story; + + private void PathAnimation() + { + 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(2)); + + 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(); + _story = new Storyboard(); + _story.RepeatBehavior = RepeatBehavior.Forever; + //story.AutoReverse = true; + _story.Children.Add(animationX); + _story.Children.Add(animationY); + _story.Children.Add(animationAngle); + 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); + + } + + private void DashAnimation() + { + this.ball.Visibility = Visibility.Collapsed; + + + var animation = new DoubleAnimation(0, -10, new Duration(TimeSpan.FromSeconds(0.5))) + { + RepeatBehavior = RepeatBehavior.Forever, + }; + Storyboard.SetTargetProperty(animation, new PropertyPath("StrokeDashOffset")); + Storyboard.SetTarget(animation, this.line); + + _story?.Stop(); + _story = new Storyboard(); + _story.RepeatBehavior = RepeatBehavior.Forever; + _story.Children.Add(animation); + _story.Begin(this); + } + + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/UserControls/TextControl.xaml.cs b/AIStudio.Wpf.DiagramDesigner/UserControls/TextControl.xaml.cs index d61317d..f96d9ad 100644 --- a/AIStudio.Wpf.DiagramDesigner/UserControls/TextControl.xaml.cs +++ b/AIStudio.Wpf.DiagramDesigner/UserControls/TextControl.xaml.cs @@ -50,6 +50,7 @@ namespace AIStudio.Wpf.DiagramDesigner if (this.DataContext is ISelectable selectable) { + selectable.PropertyChanged -= TextControl_PropertyChanged; selectable.PropertyChanged += TextControl_PropertyChanged; } TextControl_PropertyChanged(this.DataContext, new System.ComponentModel.PropertyChangedEventArgs("IsSelected")); diff --git a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectorViewModel.cs b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectorViewModel.cs index 7507db6..2641d89 100644 --- a/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectorViewModel.cs +++ b/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/ConnectorViewModel.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Media; +using AIStudio.Wpf.DiagramDesigner.Controls; using AIStudio.Wpf.DiagramDesigner.Geometrys; using AIStudio.Wpf.DiagramDesigner.Helpers; using SvgPathProperties; @@ -255,6 +256,23 @@ namespace AIStudio.Wpf.DiagramDesigner } } + + private LineAnimation _lineAnimation = LineAnimation.PathAnimation; + [Browsable(true)] + [CanDo] + [StyleName("LineAnimationStyle")] + public LineAnimation LineAnimation + { + get + { + return _lineAnimation; + } + set + { + SetProperty(ref _lineAnimation, value); + } + } + public virtual Dictionary PropertiesSetting { get