mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-20 00:06:45 +08:00
准备区分节点、参数、返回值的连接,做个备份
This commit is contained in:
93
Workbench/Node/Junction/JunctionCode.cs
Normal file
93
Workbench/Node/Junction/JunctionCode.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
|
||||
|
||||
|
||||
public abstract class JunctionControlBase : UserControl
|
||||
{
|
||||
|
||||
public double _MyWidth = 20;
|
||||
public double _MyHeight = 20;
|
||||
|
||||
protected JunctionControlBase()
|
||||
{
|
||||
//this.Width = 20;
|
||||
//this.Height = 20;
|
||||
this.MouseDown += ControlPointBase_MouseDown;
|
||||
this.MouseMove += ControlPointBase_MouseMove; ;
|
||||
}
|
||||
#region 控件属性,所在的节点
|
||||
public static readonly DependencyProperty NodeGuidProperty =
|
||||
DependencyProperty.Register("NodeGuid", typeof(string), typeof(JunctionControlBase), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// 所在的节点
|
||||
/// </summary>
|
||||
public string NodeGuid
|
||||
{
|
||||
get { return (string)GetValue(NodeGuidProperty); }
|
||||
set { SetValue(NodeGuidProperty, value.ToString()); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 控件属性,连接器类型
|
||||
public static readonly DependencyProperty JunctionTypeProperty =
|
||||
DependencyProperty.Register("JunctionType", typeof(string), typeof(JunctionControlBase), new PropertyMetadata(default(string)));
|
||||
|
||||
public JunctionType JunctionType
|
||||
{
|
||||
get { return EnumHelper.ConvertEnum<JunctionType>(GetValue(JunctionTypeProperty).ToString()); }
|
||||
set { SetValue(JunctionTypeProperty, value.ToString()); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
public abstract void Render();
|
||||
private void ControlPointBase_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (GlobalJunctionData.MyGlobalData is null) return;
|
||||
GlobalJunctionData.MyGlobalData.ChangingJunction = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在碰撞点上按下鼠标控件开始进行移动
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ControlPointBase_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
GlobalJunctionData.MyGlobalData = new ConnectingData();
|
||||
var myDataType = GlobalJunctionData.MyGlobalData;
|
||||
myDataType.StartJunction = this;
|
||||
var canvas = MainWindow.GetParentOfType<Canvas>(this);
|
||||
myDataType.StartPoint = this.TranslatePoint(new Point(this.Width /2 , this.Height /2 ), canvas);
|
||||
myDataType.VirtualLine = new MyLine(canvas, new Line // 虚拟线
|
||||
{
|
||||
Stroke = Brushes.OldLace,
|
||||
StrokeThickness = 2
|
||||
});
|
||||
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
69
Workbench/Node/Junction/JunctionData.cs
Normal file
69
Workbench/Node/Junction/JunctionData.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
|
||||
#region Model,不科学的全局变量
|
||||
public class MyLine
|
||||
{
|
||||
public MyLine(Canvas canvas, Line line)
|
||||
{
|
||||
Canvas = canvas;
|
||||
VirtualLine = line;
|
||||
canvas?.Children.Add(line);
|
||||
}
|
||||
|
||||
public Canvas Canvas { get; set; }
|
||||
public Line VirtualLine { get; set; }
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
Canvas?.Children.Remove(VirtualLine);
|
||||
}
|
||||
}
|
||||
|
||||
public class ConnectingData
|
||||
{
|
||||
public JunctionControlBase StartJunction { get; set; }
|
||||
public JunctionControlBase ChangingJunction { get; set; }
|
||||
public Point StartPoint { get; set; }
|
||||
public MyLine VirtualLine { get; set; }
|
||||
}
|
||||
|
||||
public static class GlobalJunctionData
|
||||
{
|
||||
private static ConnectingData? myGlobalData;
|
||||
|
||||
public static ConnectingData? MyGlobalData
|
||||
{
|
||||
get => myGlobalData;
|
||||
set
|
||||
{
|
||||
if (myGlobalData == null)
|
||||
{
|
||||
myGlobalData = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static bool IsCreatingConnection => myGlobalData is not null;
|
||||
|
||||
public static bool CanCreate => myGlobalData?.ChangingJunction.Equals(myGlobalData?.StartJunction) == false;
|
||||
|
||||
public static void OK()
|
||||
{
|
||||
myGlobalData?.VirtualLine.Remove();
|
||||
myGlobalData = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
237
Workbench/Node/Junction/NodeJunctionViewBase.cs
Normal file
237
Workbench/Node/Junction/NodeJunctionViewBase.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
using Serein.Workbench.Node.View;
|
||||
using System.Windows.Controls;
|
||||
using Serein.Library;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
|
||||
|
||||
public abstract class NodeJunctionViewBase : ContentControl, IDisposable
|
||||
{
|
||||
public NodeJunctionViewBase()
|
||||
{
|
||||
var transfromGroup = new TransformGroup();
|
||||
transfromGroup.Children.Add(_Translate);
|
||||
RenderTransform = transfromGroup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每个连接器都有一个唯一标识符(Guid),用于标识连接器。
|
||||
/// </summary>
|
||||
public Guid Guid
|
||||
{
|
||||
get => (Guid)GetValue(GuidProperty);
|
||||
set => SetValue(GuidProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty GuidProperty = DependencyProperty.Register(
|
||||
nameof(Guid),
|
||||
typeof(Guid),
|
||||
typeof(NodeJunctionViewBase), // NodeConnectorContent
|
||||
new PropertyMetadata(Guid.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// 连接器当前的连接数,表示有多少条 NodeLink 连接到此连接器。该属性为只读。
|
||||
/// </summary>
|
||||
public int ConnectedCount
|
||||
{
|
||||
get => (int)GetValue(ConnectedCountProperty);
|
||||
private set => SetValue(ConnectedCountPropertyKey, value);
|
||||
}
|
||||
public static readonly DependencyPropertyKey ConnectedCountPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
nameof(ConnectedCount),
|
||||
typeof(int),
|
||||
typeof(NodeJunctionViewBase), // NodeConnectorContent
|
||||
new PropertyMetadata(0));
|
||||
|
||||
public static readonly DependencyProperty ConnectedCountProperty = ConnectedCountPropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 布尔值,指示此连接器是否有任何连接。
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
get => (bool)GetValue(IsConnectedProperty);
|
||||
private set => SetValue(IsConnectedPropertyKey, value);
|
||||
}
|
||||
public static readonly DependencyPropertyKey IsConnectedPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
nameof(IsConnected),
|
||||
typeof(bool),
|
||||
typeof(NodeJunctionViewBase), // NodeConnectorContent
|
||||
new PropertyMetadata(false));
|
||||
|
||||
public static readonly DependencyProperty IsConnectedProperty = IsConnectedPropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。
|
||||
/// </summary>
|
||||
public Brush Stroke
|
||||
{
|
||||
get => (Brush)GetValue(StrokeProperty);
|
||||
set => SetValue(StrokeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
|
||||
nameof(Stroke),
|
||||
typeof(Brush),
|
||||
typeof(NodeJunctionViewBase), // NodeConnectorContent
|
||||
new FrameworkPropertyMetadata(Brushes.Blue));
|
||||
|
||||
/// <summary>
|
||||
/// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。
|
||||
/// </summary>
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => (double)GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
nameof(StrokeThickness),
|
||||
typeof(double),
|
||||
typeof(NodeJunctionViewBase), // NodeConnectorContent
|
||||
new FrameworkPropertyMetadata(1.0));
|
||||
|
||||
/// <summary>
|
||||
/// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。
|
||||
/// </summary>
|
||||
public Brush Fill
|
||||
{
|
||||
get => (Brush)GetValue(FillProperty);
|
||||
set => SetValue(FillProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
|
||||
nameof(Fill),
|
||||
typeof(Brush),
|
||||
typeof(NodeJunctionViewBase),// NodeConnectorContent
|
||||
new FrameworkPropertyMetadata(Brushes.Gray));
|
||||
|
||||
/// <summary>
|
||||
/// 指示该连接器是否可以与其他连接器进行连接。
|
||||
/// </summary>
|
||||
public bool CanConnect
|
||||
{
|
||||
get => (bool)GetValue(CanConnectProperty);
|
||||
set => SetValue(CanConnectProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty CanConnectProperty = DependencyProperty.Register(
|
||||
nameof(CanConnect),
|
||||
typeof(bool),
|
||||
typeof(NodeJunctionViewBase),// NodeConnectorContent
|
||||
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
|
||||
private Point _Position = new Point();
|
||||
/// <summary>
|
||||
/// 该连接器的当前坐标(位置)。
|
||||
/// </summary>
|
||||
public Point Position
|
||||
{
|
||||
get => _Position;
|
||||
set => UpdatePosition(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (重要数据)表示连接器所属的节点。
|
||||
/// </summary>
|
||||
public NodeModelBase NodeModel { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 该连接器所连接的所有 NodeLink 的集合。
|
||||
/// </summary>
|
||||
public IEnumerable<ConnectionControl> NodeLinks => _NodeLinks;
|
||||
List<ConnectionControl> _NodeLinks = new List<ConnectionControl>();
|
||||
|
||||
protected abstract FrameworkElement ConnectorControl { get; }
|
||||
TranslateTransform _Translate = new TranslateTransform();
|
||||
void UpdatePosition(Point pos)
|
||||
{
|
||||
_Position = pos;
|
||||
_Translate.X = _Position.X;
|
||||
_Translate.Y = _Position.Y;
|
||||
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 NodeLink 添加到连接器,并更新 ConnectedCount 和 IsConnected。
|
||||
/// </summary>
|
||||
/// <param name="nodeLink"></param>
|
||||
public void Connect(ConnectionControl nodeLink)
|
||||
{
|
||||
_NodeLinks.Add(nodeLink);
|
||||
ConnectedCount = _NodeLinks.Count;
|
||||
IsConnected = ConnectedCount > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开与某个 NodeLink 的连接,更新连接状态。
|
||||
/// </summary>
|
||||
/// <param name="nodeLink"></param>
|
||||
public void Disconnect(ConnectionControl nodeLink)
|
||||
{
|
||||
_NodeLinks.Remove(nodeLink);
|
||||
ConnectedCount = _NodeLinks.Count;
|
||||
IsConnected = ConnectedCount > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取连接器相对于指定 Canvas 的位置。
|
||||
/// </summary>
|
||||
/// <param name="canvas"></param>
|
||||
/// <param name="xScaleOffset"></param>
|
||||
/// <param name="yScaleOffset"></param>
|
||||
/// <returns></returns>
|
||||
public Point GetContentPosition(Canvas canvas, double xScaleOffset = 0.5, double yScaleOffset = 0.5)
|
||||
{
|
||||
// it will be shifted Control position if not called UpdateLayout().
|
||||
ConnectorControl.UpdateLayout();
|
||||
var transformer = ConnectorControl.TransformToVisual(canvas);
|
||||
|
||||
var x = ConnectorControl.ActualWidth * xScaleOffset;
|
||||
var y = ConnectorControl.ActualHeight * yScaleOffset;
|
||||
return transformer.Transform(new Point(x, y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新与此连接器相连的所有 NodeLink 的位置。这个方法是抽象的,要求子类实现。
|
||||
/// </summary>
|
||||
/// <param name="canvas"></param>
|
||||
public abstract void UpdateLinkPosition(Canvas canvas);
|
||||
|
||||
/// <summary>
|
||||
/// 用于检查此连接器是否可以与另一个连接器相连接,要求子类实现。
|
||||
/// </summary>
|
||||
/// <param name="connector"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool CanConnectTo(NodeJunctionViewBase connector);
|
||||
|
||||
/// <summary>
|
||||
/// 释放连接器相关的资源,包括样式、绑定和已连接的 NodeLink
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// You need to clear Style.
|
||||
// Because implemented on style for binding.
|
||||
Style = null;
|
||||
|
||||
// Clear binding for subscribing source changed event from old control.
|
||||
// throw exception about visual tree ancestor different if you not clear binding.
|
||||
BindingOperations.ClearAllBindings(this);
|
||||
|
||||
var nodeLinks = _NodeLinks.ToArray();
|
||||
|
||||
// it must instance to nodeLinks because change node link collection in NodeLink Dispose.
|
||||
foreach (var nodeLink in nodeLinks)
|
||||
{
|
||||
// nodeLink.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
54
Workbench/Node/Junction/View/ArgJunctionControl.cs
Normal file
54
Workbench/Node/Junction/View/ArgJunctionControl.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Serein.Library;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
public class ArgJunctionControl : JunctionControlBase
|
||||
{
|
||||
public ArgJunctionControl()
|
||||
{
|
||||
base.JunctionType = JunctionType.ArgData;
|
||||
Render();
|
||||
}
|
||||
|
||||
#region 控件属性,对应的参数
|
||||
public static readonly DependencyProperty ArgIndexProperty =
|
||||
DependencyProperty.Register("ArgIndex", typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int)));
|
||||
|
||||
/// <summary>
|
||||
/// 所在的节点
|
||||
/// </summary>
|
||||
public int ArgIndex
|
||||
{
|
||||
get { return (int)GetValue(ArgIndexProperty); }
|
||||
set { SetValue(ArgIndexProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
if(double.IsNaN(base.Width))
|
||||
{
|
||||
base.Width = base._MyWidth;
|
||||
}
|
||||
if (double.IsNaN(base.Height))
|
||||
{
|
||||
base.Height = base._MyHeight;
|
||||
}
|
||||
|
||||
|
||||
var ellipse = new Ellipse
|
||||
{
|
||||
Width = base.Width,
|
||||
Height = base.Height,
|
||||
Fill = Brushes.Orange,
|
||||
ToolTip = "入参"
|
||||
};
|
||||
Content = ellipse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
39
Workbench/Node/Junction/View/ExecuteJunctionControl.cs
Normal file
39
Workbench/Node/Junction/View/ExecuteJunctionControl.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Serein.Library;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
public class ExecuteJunctionControl : JunctionControlBase
|
||||
{
|
||||
//public override JunctionType JunctionType { get; } = JunctionType.Execute;
|
||||
public ExecuteJunctionControl()
|
||||
{
|
||||
base.JunctionType = JunctionType.Execute;
|
||||
Render();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
if (double.IsNaN(base.Width))
|
||||
{
|
||||
base.Width = base._MyWidth;
|
||||
}
|
||||
if (double.IsNaN(base.Height))
|
||||
{
|
||||
base.Height = base._MyHeight;
|
||||
}
|
||||
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = base.Width,
|
||||
Height = base.Height,
|
||||
Fill = Brushes.Green,
|
||||
ToolTip = "方法执行"
|
||||
};
|
||||
Content = rect;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
38
Workbench/Node/Junction/View/NextStepJunctionControl.cs
Normal file
38
Workbench/Node/Junction/View/NextStepJunctionControl.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Serein.Library;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
|
||||
public class NextStepJunctionControl : JunctionControlBase
|
||||
{
|
||||
//public override JunctionType JunctionType { get; } = JunctionType.NextStep;
|
||||
public NextStepJunctionControl()
|
||||
{
|
||||
base.JunctionType = JunctionType.NextStep;
|
||||
Render();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
if (double.IsNaN(base.Width))
|
||||
{
|
||||
base.Width = base._MyWidth;
|
||||
}
|
||||
if (double.IsNaN(base.Height))
|
||||
{
|
||||
base.Height = base._MyHeight;
|
||||
}
|
||||
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = base.Width,
|
||||
Height = base.Height,
|
||||
Fill = Brushes.Blue,
|
||||
ToolTip = "下一个方法值"
|
||||
};
|
||||
Content = rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Workbench/Node/Junction/View/ResultJunctionControl.cs
Normal file
39
Workbench/Node/Junction/View/ResultJunctionControl.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Serein.Library;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
|
||||
public class ResultJunctionControl : JunctionControlBase
|
||||
{
|
||||
//public override JunctionType JunctionType { get; } = JunctionType.ReturnData;
|
||||
|
||||
public ResultJunctionControl()
|
||||
{
|
||||
base.JunctionType = JunctionType.ReturnData;
|
||||
Render();
|
||||
}
|
||||
|
||||
public override void Render()
|
||||
{
|
||||
if (double.IsNaN(base.Width))
|
||||
{
|
||||
base.Width = base._MyWidth;
|
||||
}
|
||||
if (double.IsNaN(base.Height))
|
||||
{
|
||||
base.Height = base._MyHeight;
|
||||
}
|
||||
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = base.Width,
|
||||
Height = base.Height,
|
||||
Fill = Brushes.Red,
|
||||
ToolTip = "返回值"
|
||||
};
|
||||
Content = rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user