mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
重新设计了创建连线时的逻辑,能够预览连接成功后的外观样式
This commit is contained in:
@@ -158,25 +158,7 @@ namespace Serein.Library
|
||||
|| (start == JunctionType.ArgData && end == JunctionType.ReturnData);
|
||||
}
|
||||
|
||||
//var endType = end.ToConnectyionType();
|
||||
//if (startType != endType
|
||||
// || startType == JunctionOfConnectionType.None
|
||||
// || endType == JunctionOfConnectionType.None)
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// if (startType == JunctionOfConnectionType.Invoke)
|
||||
// {
|
||||
|
||||
// return end == JunctionType.NextStep;
|
||||
// }
|
||||
// else // if (startType == JunctionOfConnectionType.Arg)
|
||||
// {
|
||||
// return end == JunctionType.ReturnData;
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
32
Serein.Workbench.Avalonia/Api/INodeContainerControl.cs
Normal file
32
Serein.Workbench.Avalonia/Api/INodeContainerControl.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Serein.Workbench.Avalonia.Custom.Node.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Avalonia.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// 约束具有容器功能的节点控件应该有什么方法
|
||||
/// </summary>
|
||||
public interface INodeContainerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 放置一个节点
|
||||
/// </summary>
|
||||
/// <param name="nodeControl"></param>
|
||||
bool PlaceNode(NodeControlBase nodeControl);
|
||||
|
||||
/// <summary>
|
||||
/// 取出一个节点
|
||||
/// </summary>
|
||||
/// <param name="nodeControl"></param>
|
||||
bool TakeOutNode(NodeControlBase nodeControl);
|
||||
|
||||
/// <summary>
|
||||
/// 取出所有节点(用于删除容器)
|
||||
/// </summary>
|
||||
void TakeOutAll();
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,17 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Avalonia.Api
|
||||
{
|
||||
internal interface INodeControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 对应的节点实体
|
||||
/// </summary>
|
||||
NodeModelBase NodeModelBase { get; }
|
||||
//internal interface INodeControl
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 对应的节点实体
|
||||
// /// </summary>
|
||||
// NodeModelBase NodeModelBase { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化使用的方法,设置节点实体
|
||||
/// </summary>
|
||||
/// <param name="nodeModel"></param>
|
||||
void SetNodeModel(NodeModelBase nodeModel);
|
||||
}
|
||||
// /// <summary>
|
||||
// /// 初始化使用的方法,设置节点实体
|
||||
// /// </summary>
|
||||
// /// <param name="nodeModel"></param>
|
||||
// void SetNodeModel(NodeModelBase nodeModel);
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Serein.Workbench.Avalonia.Custom.Node.ViewModels
|
||||
[ObservableProperty]
|
||||
private SingleActionNode? nodeMoel;
|
||||
|
||||
|
||||
internal override NodeModelBase NodeModelBase
|
||||
{ get => NodeMoel ?? throw new NotImplementedException(); set => NodeMoel = (SingleActionNode)value; }
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Avalonia.Custom.Node.Views;
|
||||
using Serein.Workbench.Avalonia.Custom.Views;
|
||||
using Serein.Workbench.Avalonia.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -15,5 +20,117 @@ namespace Serein.Workbench.Avalonia.Custom.Node.ViewModels
|
||||
internal abstract class NodeViewModelBase : ViewModelBase
|
||||
{
|
||||
internal abstract NodeModelBase NodeModelBase { get; set; }
|
||||
|
||||
private Canvas NodeCanvas;
|
||||
|
||||
/// <summary>
|
||||
/// 如果该节点放置在了某个容器节点,就会记录这个容器节点
|
||||
/// </summary>
|
||||
private INodeContainerControl NodeContainerControl { get; }
|
||||
|
||||
public NodeModelBase NodeModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录与该节点控件有关的所有连接
|
||||
/// </summary>
|
||||
private readonly List<NodeConnectionLineView> connectionControls = new List<NodeConnectionLineView>();
|
||||
|
||||
//public NodeControlViewModelBase ViewModel { get; set; }
|
||||
|
||||
|
||||
|
||||
public void SetNodeModel(NodeModelBase nodeModel) => this.NodeModel = nodeModel;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加与该节点有关的连接后,记录下来
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
public void AddCnnection(NodeConnectionLineView connection)
|
||||
{
|
||||
connectionControls.Add(connection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除了连接之后,还需要从节点中的记录移除
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
public void RemoveConnection(NodeConnectionLineView connection)
|
||||
{
|
||||
connectionControls.Remove(connection);
|
||||
//connection.Remote();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有连接
|
||||
/// </summary>
|
||||
public void RemoveAllConection()
|
||||
{
|
||||
foreach (var connection in this.connectionControls)
|
||||
{
|
||||
//connection.Remote();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新与该节点有关的数据
|
||||
/// </summary>
|
||||
public void UpdateLocationConnections()
|
||||
{
|
||||
foreach (var connection in this.connectionControls)
|
||||
{
|
||||
//connection.RefreshLine(); // 主动更新连线位置
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置绑定:
|
||||
/// Canvas.X and Y : 画布位置
|
||||
/// </summary>
|
||||
public void SetBinding()
|
||||
{
|
||||
/* // 绑定 Canvas.Left
|
||||
Binding leftBinding = new Binding("X")
|
||||
{
|
||||
Source = ViewModel.NodeModel.Position, // 如果 X 属性在当前 DataContext 中
|
||||
Mode = BindingMode.TwoWay
|
||||
};
|
||||
BindingOperations.Apply(this, Canvas.LeftProperty, leftBinding);
|
||||
|
||||
// 绑定 Canvas.Top
|
||||
Binding topBinding = new Binding("Y")
|
||||
{
|
||||
Source = ViewModel.NodeModel.Position, // 如果 Y 属性在当前 DataContext 中
|
||||
Mode = BindingMode.TwoWay
|
||||
};
|
||||
BindingOperations.SetBinding(this, Canvas.TopProperty, topBinding);*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 穿透视觉树获取指定类型的第一个元素
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="parent"></param>
|
||||
/// <returns></returns>
|
||||
//protected T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
|
||||
//{
|
||||
// for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
||||
// {
|
||||
// var child = VisualTreeHelper.GetChild(parent, i);
|
||||
// if (child is T typedChild)
|
||||
// {
|
||||
// return typedChild;
|
||||
// }
|
||||
|
||||
// var childOfChild = FindVisualChild<T>(child);
|
||||
// if (childOfChild != null)
|
||||
// {
|
||||
// return childOfChild;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
<local:NodeControlBase xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="100"
|
||||
x:Class="Serein.Workbench.Avalonia.Custom.Node.Views.ActionNodeView"
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Avalonia.Custom.Node.ViewModels"
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Avalonia.Custom.Node.Views"
|
||||
xmlns:baselibrary="clr-namespace:Serein.Library;assembly=Serein.Library"
|
||||
xmlns:cv="clr-namespace:Serein.Workbench.Avalonia.Custom.Views"
|
||||
xmlns:dtp="using:Serein.Workbench.Avalonia.DataTemplates"
|
||||
|
||||
Background="#C6EEF7"
|
||||
Background="#C6EEF7"
|
||||
x:DataType="vm:ActionNodeViewModel">
|
||||
<Design.DataContext>
|
||||
<vm:ActionNodeViewModel />
|
||||
@@ -17,7 +18,7 @@
|
||||
|
||||
<Border>
|
||||
<Grid RowDefinitions="25,*,*,*,*">
|
||||
|
||||
|
||||
<!--调用控制点,方法名称,下一个方法调用控制点-->
|
||||
<Grid x:Name="HeaderGrid" Grid.Row="0" ColumnDefinitions="auto,*,auto" VerticalAlignment="Center">
|
||||
<cv:NodeJunctionView Grid.Column="0" JunctionType="Execute" MyNode="{Binding NodeMoel}" Width="30" Height="15" Margin="4,0,2,0" />
|
||||
@@ -42,8 +43,8 @@
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
</local:NodeControlBase>
|
||||
|
||||
@@ -2,25 +2,22 @@ using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Serein.Library;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Avalonia.Custom.Node.ViewModels;
|
||||
|
||||
namespace Serein.Workbench.Avalonia.Custom.Node.Views;
|
||||
|
||||
public partial class ActionNodeView : UserControl, INodeControl
|
||||
public partial class ActionNodeView : NodeControlBase
|
||||
{
|
||||
private ActionNodeViewModel _vm;
|
||||
|
||||
|
||||
public ActionNodeView()
|
||||
{
|
||||
InitializeComponent();
|
||||
_vm = App.GetService<ActionNodeViewModel>();
|
||||
DataContext = _vm;
|
||||
//_vm = App.GetService<ActionNodeViewModel>();
|
||||
//DataContext = _vm;
|
||||
}
|
||||
|
||||
NodeModelBase INodeControl.NodeModelBase => _vm.NodeModelBase ?? throw new System.NotImplementedException(); // ¶¯×÷½Úµã
|
||||
|
||||
void INodeControl.SetNodeModel(NodeModelBase nodeModel) // ¶¯×÷½Úµã
|
||||
{
|
||||
_vm.NodeModelBase = nodeModel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Media;
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Avalonia.Custom.Views;
|
||||
using Serein.Workbench.Avalonia.Model;
|
||||
using Serein.Workbench.Avalonia.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Avalonia.Custom.Node.Views
|
||||
{
|
||||
public class NodeControlBase : UserControl
|
||||
{
|
||||
protected NodeControlBase()
|
||||
{
|
||||
this.Background = Brushes.Transparent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 放置在某个节点容器中
|
||||
/// </summary>
|
||||
public void PlaceToContainer(INodeContainerControl nodeContainerControl)
|
||||
{
|
||||
//this.nodeContainerControl = nodeContainerControl;
|
||||
//NodeCanvas.Children.Remove(this); // 临时从画布上移除
|
||||
//var result = nodeContainerControl.PlaceNode(this);
|
||||
//if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来
|
||||
//{
|
||||
// NodeCanvas.Children.Add(this); // 从画布上移除
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从某个节点容器取出
|
||||
/// </summary>
|
||||
public void TakeOutContainer()
|
||||
{
|
||||
//var result = nodeContainerControl.TakeOutNode(this); // 从控件取出
|
||||
//if (result) // 移除成功时才添加到画布上
|
||||
//{
|
||||
// NodeCanvas.Children.Add(this); // 重新添加到画布上
|
||||
// if (nodeContainerControl is NodeControlBase containerControl)
|
||||
// {
|
||||
// NodeModel.Position.X = NodeModel.Position.X + containerControl.Width + 10;
|
||||
// NodeModel.Position.Y = NodeModel.Position.Y;
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,23 +23,22 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
{
|
||||
private readonly double strokeThickness;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 确定起始坐标和目标坐标、外光样式的曲线
|
||||
/// 确定起始坐标和目标坐标、外观样式的曲线
|
||||
/// </summary>
|
||||
/// <param name="start">起始坐标</param>
|
||||
/// <param name="end">结束坐标</param>
|
||||
/// <param name="left">起始坐标</param>
|
||||
/// <param name="right">结束坐标</param>
|
||||
/// <param name="brush">颜色</param>
|
||||
/// <param name="isDotted">是否为虚线</param>
|
||||
public ConnectionLineShape(Point start,
|
||||
Point end,
|
||||
public ConnectionLineShape(Point left,
|
||||
Point right,
|
||||
Brush brush,
|
||||
bool isDotted = false,
|
||||
bool isTop = false)
|
||||
{
|
||||
this.brush = brush;
|
||||
startPoint = start;
|
||||
endPoint = end;
|
||||
this.leftPoint = left;
|
||||
this.rightPoint = right;
|
||||
this.strokeThickness = 4;
|
||||
InitElementPoint(isDotted, isTop);
|
||||
InvalidateVisual(); // 触发重绘
|
||||
@@ -50,9 +49,10 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
{
|
||||
//hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线
|
||||
//hitVisiblePen.Freeze(); // Freeze以提高性能
|
||||
|
||||
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
||||
opacity = 1.0d;
|
||||
var dashStyle = new DashStyle();
|
||||
//var dashStyle = new DashStyle();
|
||||
|
||||
if (isDotted)
|
||||
{
|
||||
@@ -71,31 +71,44 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
/// <summary>
|
||||
/// 更新线条落点位置
|
||||
/// </summary>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="end"></param>
|
||||
public void UpdatePoints(Point start, Point end)
|
||||
/// <param name="left"></param>
|
||||
/// <param name="right"></param>
|
||||
public void UpdatePoint(Point left, Point right, Brush? brush = null)
|
||||
{
|
||||
startPoint = start;
|
||||
endPoint = end;
|
||||
if(brush is not null)
|
||||
{
|
||||
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
||||
}
|
||||
this.leftPoint = left;
|
||||
this.rightPoint = right;
|
||||
InvalidateVisual(); // 触发重绘
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新线条落点位置
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
public void UpdateEndPoints(Point point)
|
||||
/// <param name="right"></param>
|
||||
public void UpdateRightPoint(Point right, Brush? brush = null)
|
||||
{
|
||||
endPoint = point;
|
||||
if (brush is not null)
|
||||
{
|
||||
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
||||
}
|
||||
this.rightPoint = right;
|
||||
InvalidateVisual(); // 触发重绘
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新线条起点位置
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
public void UpdateStartPoints(Point point)
|
||||
/// <param name="left"></param>
|
||||
public void UpdateLeftPoints(Point left, Brush? brush = null)
|
||||
{
|
||||
startPoint = point;
|
||||
if (brush is not null)
|
||||
{
|
||||
visualPen = new Pen(brush, 3.0); // 默认可视化Pen
|
||||
}
|
||||
this.leftPoint = left;
|
||||
InvalidateVisual(); // 触发重绘
|
||||
}
|
||||
|
||||
@@ -106,7 +119,7 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
public override void Render(DrawingContext drawingContext)
|
||||
{
|
||||
// 刷新线条显示位置
|
||||
DrawBezierCurve(drawingContext, startPoint, endPoint);
|
||||
DrawBezierCurve(drawingContext, leftPoint, rightPoint);
|
||||
|
||||
}
|
||||
#region 重绘
|
||||
@@ -116,8 +129,8 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心
|
||||
//private Pen hitVisiblePen; // 初始化碰撞检测线
|
||||
private Pen visualPen; // 默认可视化Pen
|
||||
private Point startPoint; // 连接线的起始节点
|
||||
private Point endPoint; // 连接线的终点
|
||||
private Point leftPoint; // 连接线的起始节点
|
||||
private Point rightPoint; // 连接线的终点
|
||||
private Brush brush; // 线条颜色
|
||||
private double opacity; // 透明度
|
||||
|
||||
@@ -135,8 +148,8 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
private Vector startToEnd;
|
||||
private int i = 0;
|
||||
private void DrawBezierCurve(DrawingContext drawingContext,
|
||||
Point start,
|
||||
Point end)
|
||||
Point left,
|
||||
Point right)
|
||||
{
|
||||
// 控制点的计算逻辑
|
||||
double power = 140; // 控制贝塞尔曲线的“拉伸”强度
|
||||
@@ -144,7 +157,7 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
|
||||
// 计算轴向向量与起点到终点的向量
|
||||
//var axis = new Vector(1, 0);
|
||||
startToEnd = (end.ToVector() - start.ToVector()).NormalizeTo();
|
||||
startToEnd = (right.ToVector() - left.ToVector()).NormalizeTo();
|
||||
|
||||
|
||||
|
||||
@@ -163,10 +176,10 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
pow = pow > 0 ? 0 : pow;
|
||||
var k = 1 - pow;
|
||||
// 如果起点x大于终点x,增加额外的偏移量,避免重叠
|
||||
var bias = start.X > end.X ? Math.Abs(start.X - end.X) * 0.25 : 0;
|
||||
var bias = left.X > right.X ? Math.Abs(left.X - right.X) * 0.25 : 0;
|
||||
// 控制点的实际计算
|
||||
c0 = new Point(+(power + bias) * k + start.X, start.Y);
|
||||
c1 = new Point(-(power + bias) * k + end.X, end.Y);
|
||||
c0 = new Point(+(power + bias) * k + left.X, left.Y);
|
||||
c1 = new Point(-(power + bias) * k + right.X, right.Y);
|
||||
|
||||
// 准备StreamGeometry以用于绘制曲线
|
||||
// why can't clearValue()?
|
||||
@@ -204,8 +217,8 @@ namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
// streamGeometry.ClearValue("AvaloniaProperty");
|
||||
using (var context = streamGeometry.Open())
|
||||
{
|
||||
context.BeginFigure(start, true); // start point of the bezier-line
|
||||
context.CubicBezierTo(c0, c1, end, true); // drawing bezier-line
|
||||
context.BeginFigure(left, true); // start point of the bezier-line
|
||||
context.CubicBezierTo(c0, c1, right, true); // drawing bezier-line
|
||||
}
|
||||
drawingContext.DrawGeometry(null, visualPen, streamGeometry);
|
||||
|
||||
|
||||
279
Serein.Workbench.Avalonia/Custom/Views/NodeConnectionLineView.cs
Normal file
279
Serein.Workbench.Avalonia/Custom/Views/NodeConnectionLineView.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.VisualTree;
|
||||
using Serein.Library;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Workbench.Avalonia.Extension;
|
||||
using Serein.Workbench.Avalonia.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Color = Avalonia.Media.Color;
|
||||
using Point = Avalonia.Point;
|
||||
|
||||
namespace Serein.Workbench.Avalonia.Custom.Views
|
||||
{
|
||||
|
||||
|
||||
|
||||
public class NodeConnectionLineView
|
||||
{
|
||||
/// <summary>
|
||||
/// 线条类别(方法调用)
|
||||
/// </summary>
|
||||
public ConnectionInvokeType ConnectionInvokeType { get; set; } = ConnectionInvokeType.IsSucceed;
|
||||
/// <summary>
|
||||
/// 线条类别(参数传递)
|
||||
/// </summary>
|
||||
public ConnectionArgSourceType ConnectionArgSourceType { get; set; } = ConnectionArgSourceType.GetOtherNodeData;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 画布
|
||||
/// </summary>
|
||||
private Canvas Canvas;
|
||||
/// <summary>
|
||||
/// 连接线的起点
|
||||
/// </summary>
|
||||
private NodeJunctionView? LeftNodeJunctionView;
|
||||
/// <summary>
|
||||
/// 连接线的终点
|
||||
/// </summary>
|
||||
private NodeJunctionView? RightNodeJunctionView;
|
||||
|
||||
/// <summary>
|
||||
/// 连接时显示的线
|
||||
/// </summary>
|
||||
public ConnectionLineShape? ConnectionLineShape { get; private set; }
|
||||
|
||||
public NodeConnectionLineView(Canvas canvas,
|
||||
NodeJunctionView? leftNodeJunctionView,
|
||||
NodeJunctionView? rightNodeJunctionView)
|
||||
{
|
||||
this.Canvas = canvas;
|
||||
this.LeftNodeJunctionView = leftNodeJunctionView;
|
||||
this.RightNodeJunctionView = rightNodeJunctionView;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接到终点
|
||||
/// </summary>
|
||||
/// <param name="endNodeJunctionView"></param>
|
||||
public void ToEnd(NodeJunctionView endNodeJunctionView)
|
||||
{
|
||||
if((endNodeJunctionView.JunctionType == JunctionType.NextStep
|
||||
|| endNodeJunctionView.JunctionType == JunctionType.ReturnData)
|
||||
&& RightNodeJunctionView is not null
|
||||
/*&& LeftNodeJunctionView is null*/
|
||||
/*&& !LeftNodeJunctionView.Equals(endNodeJunctionView)*/)
|
||||
{
|
||||
LeftNodeJunctionView = endNodeJunctionView;
|
||||
RefreshLineDsiplay();
|
||||
return;
|
||||
}
|
||||
else if ((endNodeJunctionView.JunctionType == JunctionType.Execute
|
||||
|| endNodeJunctionView.JunctionType == JunctionType.ArgData)
|
||||
&& LeftNodeJunctionView is not null
|
||||
/*&& RightNodeJunctionView is null*/
|
||||
/*&& !RightNodeJunctionView.Equals(endNodeJunctionView)*/)
|
||||
{
|
||||
RightNodeJunctionView = endNodeJunctionView;
|
||||
RefreshLineDsiplay();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
//var leftPoint = GetPoint(LeftNodeJunctionView);
|
||||
//var rightPoint = GetPoint(RightNodeJunctionView);
|
||||
//var brush = GetBackgrounp();
|
||||
//ConnectionLineShape.UpdatePoint(leftPoint, rightPoint);
|
||||
//CreateLineShape(startPoint, endPoint, brush);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新线的显示
|
||||
/// </summary>
|
||||
public void RefreshLineDsiplay()
|
||||
{
|
||||
if(LeftNodeJunctionView is null || RightNodeJunctionView is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var leftPoint = GetPoint(LeftNodeJunctionView);
|
||||
var rightPoint = GetPoint(RightNodeJunctionView);
|
||||
if (ConnectionLineShape is null)
|
||||
{
|
||||
Debug.WriteLine("创建");
|
||||
CreateLineShape(leftPoint, rightPoint, GetBackgrounp());
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("刷新");
|
||||
var brush = GetBackgrounp();
|
||||
ConnectionLineShape.UpdatePoint( leftPoint, rightPoint, brush);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 刷新临时线的显示
|
||||
/// </summary>
|
||||
public void RefreshRightPointOfTempLineDsiplay(Point rightPoint)
|
||||
{
|
||||
if(ConnectionLineShape is not null)
|
||||
{
|
||||
var brush = GetBackgrounp();
|
||||
ConnectionLineShape.UpdateRightPoint(rightPoint, brush);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LeftNodeJunctionView is not null)
|
||||
{
|
||||
var leftPoint = GetPoint(LeftNodeJunctionView);
|
||||
var brush = GetBackgrounp();
|
||||
CreateLineShape(leftPoint, rightPoint, brush);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 刷新临时线的显示
|
||||
/// </summary>
|
||||
public void RefreshLeftPointOfTempLineDsiplay(Point leftPoint)
|
||||
{
|
||||
if(ConnectionLineShape is not null)
|
||||
{
|
||||
var brush = GetBackgrounp();
|
||||
ConnectionLineShape.UpdateLeftPoints(leftPoint, brush);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RightNodeJunctionView is not null)
|
||||
{
|
||||
var rightPoint = GetPoint(RightNodeJunctionView);
|
||||
var brush = GetBackgrounp();
|
||||
CreateLineShape(leftPoint, rightPoint, brush);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Point defaultPoint = new Point(0, 0);
|
||||
int count;
|
||||
private Point GetPoint(NodeJunctionView nodeJunctionView)
|
||||
{
|
||||
|
||||
var junctionSize = nodeJunctionView.GetTransformedBounds()!.Value.Bounds.Size;
|
||||
Point junctionPoint;
|
||||
if (nodeJunctionView.JunctionType == JunctionType.ArgData || nodeJunctionView.JunctionType == JunctionType.Execute)
|
||||
{
|
||||
junctionPoint = new Point(junctionSize.Width / 2 - 11, junctionSize.Height / 2); // 选择左侧
|
||||
}
|
||||
else
|
||||
{
|
||||
junctionPoint = new Point(junctionSize.Width / 2 + 11, junctionSize.Height / 2); // 选择右侧
|
||||
}
|
||||
if (nodeJunctionView.TranslatePoint(junctionPoint, Canvas) is Point point)
|
||||
{
|
||||
//myData.StartPoint = point;
|
||||
return point;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultPoint;
|
||||
}
|
||||
|
||||
//var point = nodeJunctionView.TranslatePoint(defaultPoint , Canvas);
|
||||
//if(point is null)
|
||||
//{
|
||||
// return defaultPoint;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return point.Value;
|
||||
// }
|
||||
}
|
||||
|
||||
private void CreateLineShape(Point leftPoint, Point rightPoint, Brush brush)
|
||||
{
|
||||
ConnectionLineShape = new ConnectionLineShape(leftPoint, rightPoint, brush);
|
||||
Canvas.Children.Add(ConnectionLineShape);
|
||||
}
|
||||
|
||||
private JunctionOfConnectionType GetConnectionType()
|
||||
{
|
||||
return LeftNodeJunctionView.JunctionType.ToConnectyionType();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取背景颜色
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Brush GetBackgrounp()
|
||||
{
|
||||
|
||||
if(LeftNodeJunctionView is null || RightNodeJunctionView is null)
|
||||
{
|
||||
return new SolidColorBrush(Color.Parse("#FF0000")); // 没有终点
|
||||
}
|
||||
|
||||
// 判断连接控制点是否匹配
|
||||
if (!IsCanConnected())
|
||||
{
|
||||
return new SolidColorBrush(Color.Parse("#FF0000"));
|
||||
}
|
||||
|
||||
|
||||
if (GetConnectionType() == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
return ConnectionInvokeType.ToLineColor(); // 调用
|
||||
}
|
||||
else
|
||||
{
|
||||
return ConnectionArgSourceType.ToLineColor(); // 参数
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool IsCanConnected()
|
||||
{
|
||||
if (LeftNodeJunctionView is null
|
||||
|| RightNodeJunctionView is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (LeftNodeJunctionView?.MyNode is null
|
||||
|| LeftNodeJunctionView.MyNode.Equals(RightNodeJunctionView.MyNode))
|
||||
return false;
|
||||
|
||||
if (LeftNodeJunctionView.JunctionType.IsCanConnection(RightNodeJunctionView.JunctionType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除线
|
||||
/// </summary>
|
||||
public void Remove()
|
||||
{
|
||||
if(ConnectionLineShape is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Canvas.Children.Remove(ConnectionLineShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,7 @@ public partial class NodeContainerView : UserControl
|
||||
{
|
||||
IsCanvasDragging = false;
|
||||
IsControlDragging = false;
|
||||
nodeOperationService.ConnectingData.Reset();
|
||||
}
|
||||
};
|
||||
#endregion
|
||||
@@ -190,12 +191,11 @@ public partial class NodeContainerView : UserControl
|
||||
|
||||
private void NodeContainerView_PointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
|
||||
// 是否正在连接
|
||||
var myData = nodeOperationService.ConnectingData;
|
||||
if (myData.IsCreateing)
|
||||
{
|
||||
var isPass = e.JudgePointer(sender, PointerType.Mouse, p => p.IsLeftButtonPressed);
|
||||
//Debug.WriteLine("canvas ispass = " + isPass);
|
||||
if (isPass)
|
||||
{
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
@@ -208,7 +208,9 @@ public partial class NodeContainerView : UserControl
|
||||
_vm.IsConnectionArgSourceNode = true; // 正在连接节点的调用关系
|
||||
}
|
||||
var currentPoint = e.GetPosition(PART_NodeContainer);
|
||||
//myData.CurrentJunction?.InvalidateVisual();
|
||||
myData.UpdatePoint(new Point(currentPoint.X - 5, currentPoint.Y - 5));
|
||||
e.Handled = true;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media;
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Avalonia.Views;
|
||||
using System.Drawing;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Avalonia.Extension;
|
||||
using System;
|
||||
using Color = Avalonia.Media.Color;
|
||||
using Point = Avalonia.Point;
|
||||
using System.Diagnostics;
|
||||
using Avalonia.Threading;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Avalonia.Extension;
|
||||
|
||||
namespace Serein.Workbench.Avalonia.Custom.Views;
|
||||
|
||||
@@ -21,55 +17,6 @@ namespace Serein.Workbench.Avalonia.Custom.Views;
|
||||
/// </summary>
|
||||
public class NodeJunctionView : TemplatedControl
|
||||
{
|
||||
private readonly INodeOperationService nodeOperationService;
|
||||
|
||||
/// <summary>
|
||||
/// Render方法中控制自绘内容
|
||||
/// </summary>
|
||||
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
|
||||
|
||||
/// <summary>
|
||||
/// 正在查看
|
||||
/// </summary>
|
||||
private bool IsPreviewing;
|
||||
|
||||
public NodeJunctionView()
|
||||
{
|
||||
nodeOperationService = App.GetService<INodeOperationService>();
|
||||
this.PointerMoved += NodeJunctionView_PointerMoved;
|
||||
this.PointerExited += NodeJunctionView_PointerExited;
|
||||
|
||||
this.PointerPressed += NodeJunctionView_PointerPressed;
|
||||
this.PointerReleased += NodeJunctionView_PointerReleased;
|
||||
}
|
||||
|
||||
private void NodeJunctionView_PointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
nodeOperationService.ConnectingData.IsCreateing = false;
|
||||
}
|
||||
|
||||
private void NodeJunctionView_PointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
nodeOperationService.TryCreateConnectionOnJunction(this); // 尝试开始创建
|
||||
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取到控件信息
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
//if (e.NameScope.Find("PART_FlipflopMethodInfos") is ListBox p_fm)
|
||||
//{
|
||||
// //p_fm.SelectionChanged += ListBox_SelectionChanged;
|
||||
// //p_fm.PointerExited += ListBox_PointerExited;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
public static readonly DirectProperty<NodeJunctionView, JunctionType> JunctionTypeProperty =
|
||||
AvaloniaProperty.RegisterDirect<NodeJunctionView, JunctionType>(nameof(JunctionType), o => o.JunctionType, (o, v) => o.JunctionType = v);
|
||||
@@ -88,6 +35,160 @@ public class NodeJunctionView : TemplatedControl
|
||||
get { return myNode; }
|
||||
set { SetAndRaise(MyNodeProperty, ref myNode, value); }
|
||||
}
|
||||
|
||||
public static readonly DirectProperty<NodeJunctionView, int> ArgIndexProperty =
|
||||
AvaloniaProperty.RegisterDirect<NodeJunctionView, int>(nameof(ArgIndex), o => o.ArgIndex, (o, v) => o.ArgIndex = v);
|
||||
private int argIndex;
|
||||
public int ArgIndex
|
||||
{
|
||||
get { return argIndex; }
|
||||
set { SetAndRaise(ArgIndexProperty, ref argIndex, value); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
private readonly INodeOperationService nodeOperationService;
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// Render方法中控制自绘内容
|
||||
/// </summary>
|
||||
protected readonly StreamGeometry StreamGeometry = new StreamGeometry();
|
||||
|
||||
|
||||
|
||||
#region 处理鼠标事件
|
||||
|
||||
|
||||
public NodeJunctionView()
|
||||
{
|
||||
nodeOperationService = App.GetService<INodeOperationService>();
|
||||
flowEnvironment = App.GetService<IFlowEnvironment>();
|
||||
//this.PointerExited += NodeJunctionView_PointerExited;
|
||||
this.PointerMoved += NodeJunctionView_PointerMoved;
|
||||
this.PointerPressed += NodeJunctionView_PointerPressed;
|
||||
this.PointerReleased += NodeJunctionView_PointerReleased;
|
||||
}
|
||||
|
||||
|
||||
public bool IsPreviewing { get; set; }
|
||||
private Guid Guid = Guid.NewGuid();
|
||||
|
||||
private void NodeJunctionView_PointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
if (!nodeOperationService.ConnectingData.IsCreateing)
|
||||
return;
|
||||
if (nodeOperationService.MainCanvas is not InputElement inputElement)
|
||||
return;
|
||||
var currentPoint = e.GetPosition(nodeOperationService.MainCanvas);
|
||||
if (inputElement.InputHitTest(currentPoint) is NodeJunctionView junctionView)
|
||||
{
|
||||
RefreshDisplay(junctionView);
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldNj = nodeOperationService.ConnectingData.CurrentJunction;
|
||||
if (oldNj is not null)
|
||||
{
|
||||
oldNj.IsPreviewing = false;
|
||||
oldNj.InvalidateVisual();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshDisplay(NodeJunctionView junctionView)
|
||||
{
|
||||
var oldNj = nodeOperationService.ConnectingData.CurrentJunction;
|
||||
if (oldNj is not null )
|
||||
{
|
||||
if (junctionView.Equals(oldNj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
oldNj.IsPreviewing = false;
|
||||
oldNj.InvalidateVisual();
|
||||
}
|
||||
nodeOperationService.ConnectingData.CurrentJunction = junctionView;
|
||||
if (!this.Equals(junctionView))
|
||||
{
|
||||
|
||||
nodeOperationService.ConnectingData.TempLine?.ToEnd(junctionView);
|
||||
}
|
||||
junctionView.IsPreviewing = true;
|
||||
junctionView.InvalidateVisual();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 尝试开始创建连接线
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void NodeJunctionView_PointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
nodeOperationService.TryCreateConnectionOnJunction(this); // 尝试开始创建
|
||||
}
|
||||
private void NodeJunctionView_PointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
CheckJunvtion();
|
||||
nodeOperationService.ConnectingData.Reset();
|
||||
}
|
||||
|
||||
private void CheckJunvtion()
|
||||
{
|
||||
var myData = nodeOperationService.ConnectingData;
|
||||
if(myData.StartJunction is null || myData.CurrentJunction is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(myData.StartJunction.MyNode is null || myData.CurrentJunction.MyNode is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!myData.IsCanConnected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var canvas = nodeOperationService.MainCanvas;
|
||||
|
||||
#region 方法调用关系创建
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
flowEnvironment.ConnectInvokeNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
|
||||
myData.StartJunction.JunctionType,
|
||||
myData.CurrentJunction.JunctionType,
|
||||
myData.ConnectionInvokeType);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 参数来源关系创建
|
||||
else if (myData.Type == JunctionOfConnectionType.Arg)
|
||||
{
|
||||
var argIndex = 0;
|
||||
if (myData.StartJunction.JunctionType == JunctionType.ArgData)
|
||||
{
|
||||
argIndex = myData.StartJunction.ArgIndex;
|
||||
}
|
||||
else if (myData.CurrentJunction.JunctionType == JunctionType.ArgData)
|
||||
{
|
||||
argIndex = myData.CurrentJunction.ArgIndex;
|
||||
}
|
||||
|
||||
flowEnvironment.ConnectArgSourceNodeAsync(myData.StartJunction.MyNode.Guid, myData.CurrentJunction.MyNode.Guid,
|
||||
myData.StartJunction.JunctionType,
|
||||
myData.CurrentJunction.JunctionType,
|
||||
myData.ConnectionArgSourceType,
|
||||
argIndex);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 重绘UI视觉
|
||||
|
||||
@@ -101,7 +202,8 @@ public class NodeJunctionView : TemplatedControl
|
||||
double width = 44;
|
||||
double height = 26;
|
||||
var background = GetBackgrounp();
|
||||
var pen = new Pen(Brushes.Black, 1);
|
||||
var pen = new Pen(Brushes.Transparent, 1);
|
||||
//var pen = nodeOperationService.ConnectingData.IsCreateing ? new Pen(background, 1) : new Pen(Brushes.Black, 1);
|
||||
|
||||
// 输入连接器的背景
|
||||
var connectorRect = new Rect(0, 0, width, height);
|
||||
@@ -132,32 +234,10 @@ public class NodeJunctionView : TemplatedControl
|
||||
context.LineTo(new Point(triangleCenterX, triangleCenterY + t), true);
|
||||
context.LineTo(new Point(triangleCenterX, triangleCenterY - t), true);
|
||||
}
|
||||
drawingContext.DrawGeometry(background, new Pen(Brushes.Black, 1), pathGeometry);
|
||||
drawingContext.DrawGeometry(background, pen, pathGeometry);
|
||||
|
||||
}
|
||||
|
||||
#region 处理鼠标事件
|
||||
|
||||
private void NodeJunctionView_PointerExited(object? sender, PointerEventArgs e)
|
||||
{
|
||||
if (IsPreviewing)
|
||||
{
|
||||
IsPreviewing = false;
|
||||
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
|
||||
}
|
||||
}
|
||||
|
||||
private void NodeJunctionView_PointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
if (!IsPreviewing)
|
||||
{
|
||||
IsPreviewing = true;
|
||||
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -167,38 +247,25 @@ public class NodeJunctionView : TemplatedControl
|
||||
protected IBrush GetBackgrounp()
|
||||
{
|
||||
var myData = nodeOperationService.ConnectingData;
|
||||
if (!myData.IsCreateing)
|
||||
if (IsPreviewing == false || !myData.IsCreateing )
|
||||
{
|
||||
//Debug.WriteLine($"return color is {Brushes.BurlyWood}");
|
||||
return new SolidColorBrush(Color.Parse("#76ABEE"));
|
||||
}
|
||||
|
||||
if (myData.IsCanConnected)
|
||||
if (!myData.IsCanConnected())
|
||||
{
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
return myData.ConnectionInvokeType.ToLineColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
return myData.ConnectionArgSourceType.ToLineColor();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brushes.Red;
|
||||
return new SolidColorBrush(Color.Parse("#FF0000"));
|
||||
}
|
||||
|
||||
if (IsPreviewing)
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
//return new SolidColorBrush(Color.Parse("#04FC10"));
|
||||
|
||||
return myData.ConnectionInvokeType.ToLineColor(); // 调用
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug.WriteLine($"return color is {Brushes.BurlyWood}");
|
||||
return new SolidColorBrush(Color.Parse("#76ABEE"));
|
||||
return myData.ConnectionArgSourceType.ToLineColor(); // 参数
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
|
||||
|
||||
<Grid ColumnDefinitions="20,40,90,auto" Margin="6,0,10,0">
|
||||
<Grid ColumnDefinitions="20,40,90,*" Margin="6,0,10,0">
|
||||
|
||||
<!--<ToolTip.Tip>
|
||||
<StackPanel>
|
||||
@@ -31,11 +31,13 @@
|
||||
</ToolTip.Tip>-->
|
||||
<!--<ToolTip Background="LightYellow" Foreground="#071042" Content="" />-->
|
||||
|
||||
<cv:NodeJunctionView Grid.Column="0" JunctionType="ArgData" MyNode="{Binding ParameterDetails.NodeModel}" Width="30" Height="15" Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<cv:NodeJunctionView Grid.Column="0" JunctionType="ArgData" ArgIndex="{Binding ParameterDetails.Index}" MyNode="{Binding ParameterDetails.NodeModel}" Width="30" Height="15" Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
|
||||
<!--指定参数-->
|
||||
<CheckBox Grid.Column="1" IsChecked="{Binding ParameterDetails.IsExplicitData, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" >
|
||||
|
||||
</CheckBox>
|
||||
<!--<TextBlock Grid.Column="2" Text="{Binding ParameterDetails.Index, StringFormat='arg{0} '}" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" />-->
|
||||
<!--参数名称-->
|
||||
<TextBlock Grid.Column="2" Text="{Binding ParameterDetails.Name}" FontSize="14"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
ToolTip.Placement="Bottom" ToolTip.VerticalOffset="6">
|
||||
@@ -45,12 +47,16 @@
|
||||
</StackPanel>
|
||||
</ToolTip.Tip>
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="3" IsVisible="{Binding IsVisibleA}" FontSize="14" Text=" [ 自动取参 ]" MinWidth="100" MaxWidth="300" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
||||
<TextBox Grid.Column="3" IsVisible="{Binding IsVisibleB}" FontSize="14" Text="{Binding ParameterDetails.DataValue, Mode=TwoWay}" MinWidth="100" MaxWidth="300" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
||||
<!--参数内容-->
|
||||
<TextBlock Grid.Column="3" IsVisible="{Binding IsVisibleA}" FontSize="14" Text=" [ 自动取参 ]"
|
||||
MinWidth="120" MaxWidth="300" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
||||
<TextBox Grid.Column="3" IsVisible="{Binding IsVisibleB}" FontSize="14" Text="{Binding ParameterDetails.DataValue, Mode=TwoWay}"
|
||||
MinWidth="120" MaxWidth="300" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
||||
<ComboBox Grid.Column="3" IsVisible="{Binding IsVisibleC}"
|
||||
ItemsSource="{Binding ParameterDetails.Items}"
|
||||
SelectedValue="{Binding ParameterDetails.DataValue,Mode=OneTime}"
|
||||
MinWidth="100" MaxWidth="300">
|
||||
MinWidth="120" MaxWidth="300"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" FontFamily="{Binding}" FontSize="14"/>
|
||||
|
||||
@@ -30,12 +30,7 @@ namespace Serein.Workbench.Avalonia.DataTemplates
|
||||
textBlock.Margin = new Thickness(2d, -6d, 2d, -6d);
|
||||
textBlock.FontSize = 12;
|
||||
textBlock.PointerPressed += TextBlock_PointerPressed;
|
||||
//var stackPanel = new StackPanel();
|
||||
//stackPanel.Children.Add(textBlock);
|
||||
//ToolTip toolTip = new ToolTip();
|
||||
//toolTip.FontSize = 12;
|
||||
//toolTip.Content = mdInfo.MethodAnotherName;
|
||||
//textBlock.Tag = mdInfo;
|
||||
textBlock.Tag = mdInfo;
|
||||
return textBlock;
|
||||
}
|
||||
else
|
||||
@@ -43,7 +38,6 @@ namespace Serein.Workbench.Avalonia.DataTemplates
|
||||
var textBlock = new TextBlock() { Text = $"Binding 类型不为预期的[MethodDetailsInfo],而是[{param?.GetType()}]" };
|
||||
textBlock.Margin = new Thickness(2d, -6d, 2d, -6d);
|
||||
textBlock.FontSize = 12;
|
||||
textBlock.PointerPressed += TextBlock_PointerPressed;
|
||||
return textBlock;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Threading;
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Avalonia.Custom.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -34,7 +36,7 @@ namespace Serein.Workbench.Avalonia.Model
|
||||
/// <summary>
|
||||
/// 线条样式
|
||||
/// </summary>
|
||||
public MyLine? TempLine { get; set; }
|
||||
public NodeConnectionLineView? TempLine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 线条类别(方法调用)
|
||||
@@ -49,59 +51,56 @@ namespace Serein.Workbench.Avalonia.Model
|
||||
/// 判断当前连接类型
|
||||
/// </summary>
|
||||
public JunctionOfConnectionType? Type => StartJunction?.JunctionType.ToConnectyionType();
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许连接
|
||||
/// </summary>
|
||||
|
||||
public bool IsCanConnected
|
||||
public bool IsCanConnected()
|
||||
{
|
||||
get
|
||||
if (StartJunction is null
|
||||
|| CurrentJunction is null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (StartJunction?.MyNode is null
|
||||
|| StartJunction.MyNode.Equals(CurrentJunction.MyNode))
|
||||
return false;
|
||||
|
||||
if (StartJunction is null
|
||||
|| CurrentJunction is null
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(StartJunction?.MyNode is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode)
|
||||
&& StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新临时的连接线
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
public void UpdatePoint(Point point)
|
||||
{
|
||||
if (StartJunction is null
|
||||
|| CurrentJunction is null
|
||||
)
|
||||
if (StartJunction is null || CurrentJunction is null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (IsCanConnected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (StartJunction.JunctionType == Library.JunctionType.Execute
|
||||
|| StartJunction.JunctionType == Library.JunctionType.ArgData)
|
||||
{
|
||||
TempLine?.Line.UpdateStartPoints(point);
|
||||
TempLine?.RefreshLeftPointOfTempLineDsiplay(point);
|
||||
}
|
||||
else
|
||||
{
|
||||
TempLine?.Line.UpdateEndPoints(point);
|
||||
TempLine?.RefreshRightPointOfTempLineDsiplay(point);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -111,9 +110,17 @@ namespace Serein.Workbench.Avalonia.Model
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
if(CurrentJunction is not null)
|
||||
{
|
||||
CurrentJunction.IsPreviewing = false;
|
||||
Dispatcher.UIThread.InvokeAsync(CurrentJunction.InvalidateVisual, DispatcherPriority.Background);
|
||||
}
|
||||
if(StartJunction is not null)
|
||||
{
|
||||
StartJunction.IsPreviewing = false;
|
||||
Dispatcher.UIThread.InvokeAsync(StartJunction.InvalidateVisual, DispatcherPriority.Background);
|
||||
}
|
||||
IsCreateing = false;
|
||||
StartJunction = null;
|
||||
CurrentJunction = null;
|
||||
TempLine?.Remove();
|
||||
ConnectionInvokeType = ConnectionInvokeType.IsSucceed;
|
||||
ConnectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData;
|
||||
|
||||
@@ -12,20 +12,21 @@ namespace Serein.Workbench.Avalonia.Model
|
||||
/// <summary>
|
||||
/// 绘制的线
|
||||
/// </summary>
|
||||
public class MyLine
|
||||
public class NodeConnectionLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 将线条绘制出来
|
||||
/// 将线条绘制出来(临时线)
|
||||
/// </summary>
|
||||
/// <param name="canvas">放置画布</param>
|
||||
/// <param name="line">线的实体</param>
|
||||
public MyLine(Canvas canvas, ConnectionLineShape line)
|
||||
public NodeConnectionLine(Canvas canvas, ConnectionLineShape line)
|
||||
{
|
||||
Canvas = canvas;
|
||||
Line = line;
|
||||
canvas?.Children.Add(line);
|
||||
}
|
||||
|
||||
|
||||
public Canvas Canvas { get; }
|
||||
public ConnectionLineShape Line { get; }
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Custom\ViewModels\FlowLibraryInfoViewModel.cs" />
|
||||
<Compile Remove="Model\NodeConnectionLine.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -15,6 +15,7 @@ using Serein.Workbench.Avalonia.Extension;
|
||||
using Serein.Workbench.Avalonia.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -81,12 +82,12 @@ namespace Serein.Workbench.Avalonia.Api
|
||||
|
||||
internal class NodeViewCreateEventArgs : EventArgs
|
||||
{
|
||||
internal NodeViewCreateEventArgs(INodeControl nodeControl, PositionOfUI position)
|
||||
internal NodeViewCreateEventArgs(NodeControlBase nodeControl, PositionOfUI position)
|
||||
{
|
||||
this.NodeControl = nodeControl;
|
||||
this.Position = position;
|
||||
}
|
||||
public INodeControl NodeControl { get; private set; }
|
||||
public NodeControlBase NodeControl { get; private set; }
|
||||
public PositionOfUI Position { get; private set; }
|
||||
}
|
||||
|
||||
@@ -112,11 +113,9 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
{
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
this.feefService = feefService;
|
||||
|
||||
NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeView), typeof(ActionNodeViewModel)); // 注册动作节点
|
||||
ConnectingData = new ConnectingData();
|
||||
feefService.OnNodeCreate += FeefService_OnNodeCreate; // 订阅运行环境创建节点事件
|
||||
|
||||
feefService.OnNodeConnectChange += FeefService_OnNodeConnectChange; // 订阅运行环境连接了节点事件
|
||||
NodeMVVMManagement.RegisterUI(NodeControlType.Action, typeof(ActionNodeView), typeof(ActionNodeViewModel)); // 注册动作节点
|
||||
|
||||
// 手动加载项目
|
||||
_ = Task.Run(async delegate
|
||||
@@ -133,17 +132,24 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
|
||||
}
|
||||
|
||||
public ConnectingData ConnectingData { get; private set; }
|
||||
|
||||
#region 接口属性
|
||||
public ConnectingData ConnectingData { get; private set; } = new ConnectingData();
|
||||
public Canvas MainCanvas { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有变量
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有与节点有关的控件
|
||||
/// </summary>
|
||||
private Dictionary<string, INodeControl> NodeControls { get; } = [];
|
||||
private Dictionary<string, NodeControlBase> NodeControls { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有连接
|
||||
/// </summary>
|
||||
private List<NodeConnectionLineView> Connections { get; } = [];
|
||||
|
||||
|
||||
|
||||
@@ -158,28 +164,16 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
private readonly IFlowEEForwardingService feefService;
|
||||
#endregion
|
||||
|
||||
#region 节点操作事件
|
||||
|
||||
/// <summary>
|
||||
/// 创建了节点控件
|
||||
/// </summary>
|
||||
public event NodeViewCreateHandle OnNodeViewCreate;
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点控件
|
||||
/// </summary>
|
||||
/// <param name="nodeType">控件类型</param>
|
||||
/// <param name="position">创建坐标</param>
|
||||
/// <param name="methodDetailsInfo">节点方法信息(基础节点传null)</param>
|
||||
public void CreateNodeView(MethodDetailsInfo methodDetailsInfo, PositionOfUI position)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (EnumHelper.TryConvertEnum<NodeControlType>(methodDetailsInfo.NodeType, out var nodeType))
|
||||
{
|
||||
await flowEnvironment.CreateNodeAsync(nodeType, position, methodDetailsInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 转发事件的处理
|
||||
|
||||
/// <summary>
|
||||
/// 从工作台事件转发器监听节点创建事件
|
||||
@@ -225,6 +219,178 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 运行环境连接了节点事件
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void FeefService_OnNodeConnectChange(NodeConnectChangeEventArgs eventArgs)
|
||||
{
|
||||
#if false
|
||||
string fromNodeGuid = eventArgs.FromNodeGuid;
|
||||
string toNodeGuid = eventArgs.ToNodeGuid;
|
||||
if (!TryGetControl(fromNodeGuid, out var fromNodeControl)
|
||||
|| !TryGetControl(toNodeGuid, out var toNodeControl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventArgs.JunctionOfConnectionType == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
ConnectionInvokeType connectionType = eventArgs.ConnectionInvokeType;
|
||||
#region 创建/删除节点之间的调用关系
|
||||
#region 创建连接
|
||||
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
var startJunction = IFormJunction.NextStepJunction;
|
||||
var endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
startJunction.TransformToVisual(MainCanvas);
|
||||
|
||||
// 添加连接
|
||||
var shape = new ConnectionLineShape(
|
||||
FlowChartCanvas,
|
||||
connectionType,
|
||||
startJunction,
|
||||
endJunction
|
||||
);
|
||||
NodeConnectionLine nodeConnectionLine = new NodeConnectionLine(MainCanvas, shape);
|
||||
|
||||
//if (toNodeControl is FlipflopNodeControl flipflopControl
|
||||
// && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
|
||||
//{
|
||||
// NodeTreeViewer.RemoveGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
||||
//}
|
||||
|
||||
Connections.Add(nodeConnectionLine);
|
||||
fromNodeControl.AddCnnection(shape);
|
||||
toNodeControl.AddCnnection(shape);
|
||||
}
|
||||
#endregion
|
||||
#if false
|
||||
|
||||
#region 移除连接
|
||||
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remove) // 移除连接
|
||||
{
|
||||
// 需要移除连接
|
||||
var removeConnections = Connections.Where(c =>
|
||||
c.Start.MyNode.Guid.Equals(fromNodeGuid)
|
||||
&& c.End.MyNode.Guid.Equals(toNodeGuid)
|
||||
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
|
||||
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
|
||||
.ToList();
|
||||
|
||||
|
||||
foreach (var connection in removeConnections)
|
||||
{
|
||||
Connections.Remove(connection);
|
||||
fromNodeControl.RemoveConnection(connection); // 移除连接
|
||||
toNodeControl.RemoveConnection(connection); // 移除连接
|
||||
if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||
{
|
||||
JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#if false
|
||||
ConnectionArgSourceType connectionArgSourceType = eventArgs.ConnectionArgSourceType;
|
||||
#region 创建/删除节点之间的参数传递关系
|
||||
#region 创建连接
|
||||
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的情况");
|
||||
return;
|
||||
}
|
||||
|
||||
JunctionControlBase startJunction = eventArgs.ConnectionArgSourceType switch
|
||||
{
|
||||
ConnectionArgSourceType.GetPreviousNodeData => IFormJunction.ReturnDataJunction, // 自身节点
|
||||
ConnectionArgSourceType.GetOtherNodeData => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||
ConnectionArgSourceType.GetOtherNodeDataOfInvoke => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||
_ => throw new Exception("窗体事件 FlowEnvironment_NodeConnectChangeEvemt 创建/删除节点之间的参数传递关系 JunctionControlBase 枚举值错误 。非预期的枚举值。") // 应该不会触发
|
||||
};
|
||||
|
||||
if (IToJunction.ArgDataJunction.Length <= eventArgs.ArgIndex)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(500);
|
||||
FlowEnvironment_NodeConnectChangeEvemt(eventArgs);
|
||||
});
|
||||
return;
|
||||
}
|
||||
JunctionControlBase endJunction = IToJunction.ArgDataJunction[eventArgs.ArgIndex];
|
||||
LineType lineType = LineType.Bezier;
|
||||
// 添加连接
|
||||
var connection = new ConnectionControl(
|
||||
lineType,
|
||||
FlowChartCanvas,
|
||||
eventArgs.ArgIndex,
|
||||
eventArgs.ConnectionArgSourceType,
|
||||
startJunction,
|
||||
endJunction,
|
||||
IToJunction
|
||||
);
|
||||
Connections.Add(connection);
|
||||
fromNodeControl.AddCnnection(connection);
|
||||
toNodeControl.AddCnnection(connection);
|
||||
EndConnection(); // 环境触发了创建节点连接事件
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region 移除连接
|
||||
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remove) // 移除连接
|
||||
{
|
||||
// 需要移除连接
|
||||
var removeConnections = Connections.Where(c => c.Start.MyNode.Guid.Equals(fromNodeGuid)
|
||||
&& c.End.MyNode.Guid.Equals(toNodeGuid))
|
||||
.ToList(); // 获取这两个节点之间的所有连接关系
|
||||
|
||||
|
||||
|
||||
foreach (var connection in removeConnections)
|
||||
{
|
||||
if (connection.End is ArgJunctionControl junctionControl && junctionControl.ArgIndex == eventArgs.ArgIndex)
|
||||
{
|
||||
// 找到符合删除条件的连接线
|
||||
Connections.Remove(connection); // 从本地记录中移除
|
||||
fromNodeControl.RemoveConnection(connection); // 从节点持有的记录移除
|
||||
toNodeControl.RemoveConnection(connection); // 从节点持有的记录移除
|
||||
}
|
||||
|
||||
|
||||
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||
//{
|
||||
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||
//}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点控件
|
||||
/// </summary>
|
||||
@@ -234,7 +400,7 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
/// <param name="nodeView">返回的节点对象</param>
|
||||
/// <returns>是否创建成功</returns>
|
||||
/// <exception cref="Exception">无法创建节点控件</exception>
|
||||
private bool TryCreateNodeView(Type viewType, Type viewModelType, NodeModelBase nodeModel, out INodeControl? nodeView)
|
||||
private bool TryCreateNodeView(Type viewType, Type viewModelType, NodeModelBase nodeModel, out NodeControlBase? nodeView)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeModel.Guid))
|
||||
{
|
||||
@@ -248,16 +414,16 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
}
|
||||
viewModelBase.NodeModelBase = nodeModel; // 设置节点对象
|
||||
var controlObj = Activator.CreateInstance(viewType);
|
||||
if (controlObj is not INodeControl nodeControl)
|
||||
if (controlObj is NodeControlBase nodeControl)
|
||||
{
|
||||
nodeView = null;
|
||||
return false;
|
||||
nodeControl.DataContext = viewModelBase;
|
||||
nodeView = nodeControl;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeControl.SetNodeModel(nodeModel);
|
||||
nodeView = nodeControl;
|
||||
return true;
|
||||
nodeView = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 在其它地方验证过了,所以注释
|
||||
@@ -276,6 +442,47 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
//}
|
||||
}
|
||||
|
||||
private bool TryGetControl(string nodeGuid, out NodeControlBase nodeControl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nodeGuid))
|
||||
{
|
||||
nodeControl = null;
|
||||
return false;
|
||||
}
|
||||
if (!NodeControls.TryGetValue(nodeGuid, out nodeControl))
|
||||
{
|
||||
nodeControl = null;
|
||||
return false;
|
||||
}
|
||||
if (nodeControl is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 操作接口对外暴露的接口
|
||||
|
||||
/// <summary>
|
||||
/// 创建节点控件
|
||||
/// </summary>
|
||||
/// <param name="nodeType">控件类型</param>
|
||||
/// <param name="position">创建坐标</param>
|
||||
/// <param name="methodDetailsInfo">节点方法信息(基础节点传null)</param>
|
||||
public void CreateNodeView(MethodDetailsInfo methodDetailsInfo, PositionOfUI position)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (EnumHelper.TryConvertEnum<NodeControlType>(methodDetailsInfo.NodeType, out var nodeType))
|
||||
{
|
||||
await flowEnvironment.CreateNodeAsync(nodeType, position, methodDetailsInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 尝试在连接控制点之间创建连接线
|
||||
/// </summary>
|
||||
@@ -283,25 +490,23 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
{
|
||||
if (MainCanvas is not null)
|
||||
{
|
||||
var myData = ConnectingData;
|
||||
var junctionSize = startJunction.GetTransformedBounds()!.Value.Bounds.Size;
|
||||
var junctionPoint = new Point(junctionSize.Width / 2, junctionSize.Height / 2);
|
||||
if (startJunction.TranslatePoint(junctionPoint, MainCanvas) is Point point)
|
||||
ConnectingData.Reset();
|
||||
ConnectingData.IsCreateing = true; // 表示开始连接
|
||||
ConnectingData.StartJunction = startJunction;
|
||||
ConnectingData.CurrentJunction = startJunction;
|
||||
if(startJunction.JunctionType == JunctionType.NextStep || startJunction.JunctionType == JunctionType.ReturnData)
|
||||
{
|
||||
myData.StartPoint = point;
|
||||
|
||||
ConnectingData.TempLine = new NodeConnectionLineView(MainCanvas, startJunction, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
ConnectingData.TempLine = new NodeConnectionLineView(MainCanvas,null ,startJunction);
|
||||
}
|
||||
|
||||
myData.Reset();
|
||||
myData.IsCreateing = true; // 表示开始连接
|
||||
myData.StartJunction = startJunction;
|
||||
myData.CurrentJunction = startJunction;
|
||||
|
||||
var junctionOfConnectionType = startJunction.JunctionType.ToConnectyionType();
|
||||
ConnectionLineShape bezierLine; // 类别
|
||||
/*var junctionOfConnectionType = startJunction.JunctionType.ToConnectyionType();
|
||||
ConnectionLineShape bezierLine;
|
||||
Brush brushColor; // 临时线的颜色
|
||||
if (junctionOfConnectionType == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
@@ -319,11 +524,13 @@ namespace Serein.Workbench.Avalonia.Services
|
||||
myData.StartPoint,
|
||||
brushColor,
|
||||
isTop: true); // 绘制临时的线
|
||||
|
||||
*/
|
||||
//Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线
|
||||
myData.TempLine = new MyLine(MainCanvas, bezierLine);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<Grid Grid.Row="2" Grid.Column="0"
|
||||
RowDefinitions="*" ColumnDefinitions="auto,*">
|
||||
<!--依赖信息-->
|
||||
<Grid RowDefinitions="*,auto" HorizontalAlignment="Left">
|
||||
<Grid IsVisible="False" RowDefinitions="*,auto" HorizontalAlignment="Left">
|
||||
<!--已加载的依赖-->
|
||||
<cv:FlowLibrarysView Grid.Row="0"/>
|
||||
<!--<cv:FlowLibraryMethodInfoView Grid.Row="1" HorizontalAlignment="Left"/>-->
|
||||
|
||||
@@ -18,8 +18,7 @@ namespace Serein.Workbench.Node.View
|
||||
InitializeComponent();
|
||||
if(ExecuteJunctionControl.MyNode != null)
|
||||
{
|
||||
|
||||
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
|
||||
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user