diff --git a/Workbench/Extension/LineExtension.cs b/Workbench/Extension/LineExtension.cs deleted file mode 100644 index ce0eb42..0000000 --- a/Workbench/Extension/LineExtension.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Serein.Library; -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Media; - -namespace Serein.Workbench.Extension -{ - /// - /// 线条颜色 - /// - public static class LineExtension - { - /// - /// 根据连接类型指定颜色 - /// - /// - /// - /// - public static SolidColorBrush ToLineColor(this ConnectionInvokeType currentConnectionType) - { - return currentConnectionType switch - { - ConnectionInvokeType.IsSucceed => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10")), // 04FC10 & 027E08 - ConnectionInvokeType.IsFail => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F18905")), - ConnectionInvokeType.IsError => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FE1343")), - ConnectionInvokeType.Upstream => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#4A82E4")), - ConnectionInvokeType.None => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), - _ => throw new Exception(), - }; - } - /// - /// 根据连接类型指定颜色 - /// - /// - /// - /// - public static SolidColorBrush ToLineColor(this ConnectionArgSourceType connection) - { - return connection switch - { - ConnectionArgSourceType.GetPreviousNodeData => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), // 04FC10 & 027E08 - ConnectionArgSourceType.GetOtherNodeData => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#56CEF6")), - ConnectionArgSourceType.GetOtherNodeDataOfInvoke => new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B06BBB")), - _ => throw new Exception(), - }; - } - - } -} diff --git a/Workbench/Extension/MyExtension.cs b/Workbench/Extension/MyExtension.cs deleted file mode 100644 index 0bacb12..0000000 --- a/Workbench/Extension/MyExtension.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Serein.Workbench.Extension -{ - public static class PointExtension - { - public static Point Add(this Point a, Point b) - { - return new Point(a.X + b.X, a.Y + b.Y); - } - - public static Point Sub(this Point a, Point b) - { - return new Point(a.X - b.X, a.Y - b.Y); - } - - public static Vector ToVector(this Point me) - { - return new Vector(me.X, me.Y); - } - } - public static class VectorExtension - { - public static double DotProduct(this Vector a, Vector b) - { - return a.X * b.X + a.Y * b.Y; - } - - public static Vector NormalizeTo(this Vector v) - { - var temp = v; - temp.Normalize(); - - return temp; - } - } -} diff --git a/Workbench/Node/INodeContainerControl.cs b/Workbench/Node/INodeContainerControl.cs deleted file mode 100644 index 4c01eff..0000000 --- a/Workbench/Node/INodeContainerControl.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.Workbench.Node -{ - - /// - /// 约束具有容器功能的节点控件应该有什么方法 - /// - public interface INodeContainerControl - { - /// - /// 放置一个节点 - /// - /// - bool PlaceNode(NodeControlBase nodeControl); - - /// - /// 取出一个节点 - /// - /// - bool TakeOutNode(NodeControlBase nodeControl); - - /// - /// 取出所有节点(用于删除容器) - /// - void TakeOutAll(); - } -} diff --git a/Workbench/Node/INodeJunction.cs b/Workbench/Node/INodeJunction.cs deleted file mode 100644 index ae74d0d..0000000 --- a/Workbench/Node/INodeJunction.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Serein.Workbench.Node -{ - - - - /// - /// 约束一个节点应该有哪些控制点 - /// - public interface INodeJunction - { - /// - /// 方法执行入口控制点 - /// - JunctionControlBase ExecuteJunction { get; } - /// - /// 执行完成后下一个要执行的方法控制点 - /// - JunctionControlBase NextStepJunction { get; } - - /// - /// 参数节点控制点 - /// - JunctionControlBase[] ArgDataJunction { get; } - /// - /// 返回值控制点 - /// - JunctionControlBase ReturnDataJunction { get; } - - /// - /// 获取目标参数控制点,用于防止wpf释放资源导致找不到目标节点,返回-1,-1的坐标 - /// - /// - /// - JunctionControlBase GetJunctionOfArgData(int index) - { - var arr = ArgDataJunction; - if (index >= arr.Length) - { - return null; - } - return arr[index]; - } - } -} diff --git a/Workbench/Node/Junction/ConnectionLineShape.cs b/Workbench/Node/Junction/ConnectionLineShape.cs deleted file mode 100644 index 122adaf..0000000 --- a/Workbench/Node/Junction/ConnectionLineShape.cs +++ /dev/null @@ -1,234 +0,0 @@ -using Serein.Library; -using Serein.Workbench.Extension; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; - -namespace Serein.Workbench.Node.View -{ - /// - /// 连接线的类型 - /// - public enum LineType - { - /// - /// 贝塞尔曲线 - /// - Bezier, - /// - /// 半圆线 - /// - Semicircle, - } - - - - /// - /// 贝塞尔曲线 - /// - public class ConnectionLineShape : Shape - { - private readonly double strokeThickness; - - private readonly LineType lineType; - - /// - /// 确定起始坐标和目标坐标、外光样式的曲线 - /// - /// 线条类型 - /// 起始坐标 - /// 结束坐标 - /// 颜色 - /// 是否为虚线 - public ConnectionLineShape(LineType lineType, - Point start, - Point end, - Brush brush, - bool isDotted = false, - bool isTop = false) - { - this.lineType = lineType; - this.brush = brush; - startPoint = start; - endPoint = end; - this.strokeThickness = 4; - InitElementPoint(isDotted, isTop); - InvalidateVisual(); // 触发重绘 - } - - - public void InitElementPoint(bool isDotted , bool isTop = false) - { - hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线 - hitVisiblePen.Freeze(); // Freeze以提高性能 - visualPen = new Pen(brush, 3.0); // 默认可视化Pen - opacity = 1.0d; - if (isDotted) - { - opacity = 0.42d; - visualPen.DashStyle = DashStyles.Dash; // 选择虚线样式 - } - visualPen.Freeze(); // Freeze以提高性能 - - linkSize = 4; // 整线条粗细 - int zIndex = -999999; - if (isTop) - { - zIndex *= -1; - } - Panel.SetZIndex(this, zIndex); // 置底 - } - - /// - /// 更新线条落点位置 - /// - /// - /// - public void UpdatePoints(Point start, Point end) - { - startPoint = start; - endPoint = end; - InvalidateVisual(); // 触发重绘 - } - - /// - /// 更新线条落点位置 - /// - /// - public void UpdateEndPoints(Point point) - { - endPoint = point; - InvalidateVisual(); // 触发重绘 - } - /// - /// 更新线条落点位置 - /// - /// - public void UpdateStartPoints(Point point) - { - startPoint = point; - InvalidateVisual(); // 触发重绘 - } - - /// - /// 控件重绘事件 - /// - /// - protected override void OnRender(DrawingContext drawingContext) - { - // 刷新线条显示位置 - switch (this.lineType) - { - case LineType.Bezier: - DrawBezierCurve(drawingContext, startPoint, endPoint); - break; - case LineType.Semicircle: - DrawSemicircleCurve(drawingContext, startPoint, endPoint); - break; - default: - break; - } - - } - #region 重绘 - - private readonly StreamGeometry streamGeometry = new StreamGeometry(); - private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心 - private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心 - private Pen hitVisiblePen; // 初始化碰撞检测线 - private Pen visualPen; // 默认可视化Pen - private Point startPoint; // 连接线的起始节点 - private Point endPoint; // 连接线的终点 - private Brush brush; // 线条颜色 - private double opacity; // 透明度 - - double linkSize; // 根据缩放比例调整线条粗细 - protected override Geometry DefiningGeometry => streamGeometry; - - public void UpdateLineColor(Brush brush) - { - visualPen = new Pen(brush, 3.0); // 默认可视化Pen - InvalidateVisual(); // 触发重绘 - } - - - private Point c0, c1; // 用于计算贝塞尔曲线控制点逻辑 - private Vector axis = new Vector(1, 0); - private Vector startToEnd; - private void DrawBezierCurve(DrawingContext drawingContext, - Point start, - Point end) - { - // 控制点的计算逻辑 - double power = 140; // 控制贝塞尔曲线的“拉伸”强度 - drawingContext.PushOpacity(opacity); - // 计算轴向向量与起点到终点的向量 - //var axis = new Vector(1, 0); - startToEnd = (end.ToVector() - start.ToVector()).NormalizeTo(); - - // 计算拉伸程度k,拉伸与水平夹角正相关 - var k = 1 - Math.Pow(Math.Max(0, axis.DotProduct(startToEnd)), 10.0); - - // 如果起点x大于终点x,增加额外的偏移量,避免重叠 - var bias = start.X > end.X ? Math.Abs(start.X - end.X) * 0.25 : 0; - - // 控制点的实际计算 - c0 = new Point(+(power + bias) * k + start.X, start.Y); - c1 = new Point(-(power + bias) * k + end.X, end.Y); - - // 准备StreamGeometry以用于绘制曲线 - streamGeometry.Clear(); - using (var context = streamGeometry.Open()) - { - context.BeginFigure(start, true, false); // 曲线起点 - context.BezierTo(c0, c1, end, true, false); // 画贝塞尔曲线 - } - drawingContext.DrawGeometry(null, visualPen, streamGeometry); - - } - - - - private void DrawSemicircleCurve(DrawingContext drawingContext, Point start, Point end) - { - // 计算中心点和半径 - // 计算圆心和半径 - double x = 35; - // 创建一个弧线路径 - streamGeometry.Clear(); - using (var context = streamGeometry.Open()) - { - // 开始绘制 - context.BeginFigure(start, false, false); - - // 生成弧线 - context.ArcTo( - end, // 结束点 - new Size(x, x), // 椭圆的半径 - 0, // 椭圆的旋转角度 - false, // 是否大弧 - SweepDirection.Counterclockwise, // 方向 - true, // 是否连接到起始点 - true // 是否使用高质量渲染 - ); - - // 结束绘制 - context.LineTo(start, false, false); // 连接到起始点(可选) - } - - // 绘制弧线 - drawingContext.DrawGeometry(null, visualPen, streamGeometry); - - } - #endregion - } - - -} diff --git a/Workbench/Node/Junction/JunctionControlBase.cs b/Workbench/Node/Junction/JunctionControlBase.cs deleted file mode 100644 index 5ce870c..0000000 --- a/Workbench/Node/Junction/JunctionControlBase.cs +++ /dev/null @@ -1,378 +0,0 @@ -using Serein.Library; -using Serein.Library.Utils; -using System; -using System.Net; -using System.Reflection; -using System.Windows; -using Serein.Workbench.Extension; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Shapes; -using System.Windows.Media.Media3D; -using System.Windows.Documents; -using System.Threading; - -namespace Serein.Workbench.Node.View -{ - internal static class MyUIFunc - { - public static Pen CreateAndFreezePen() - { - // 创建Pen - Pen pen = new Pen(Brushes.Black, 1); - - // 冻结Pen - if (pen.CanFreeze) - { - pen.Freeze(); - } - return pen; - } - } - - public class ParamsArgControl: Shape - { - - - public ParamsArgControl() - { - this.MouseDown += ParamsArg_OnMouseDown; // 增加或删除 - this.MouseMove += ParamsArgControl_MouseMove; - this.MouseLeave += ParamsArgControl_MouseLeave; - AddOrRemoveParamsTask = AddAsync; - } - - - - protected readonly StreamGeometry StreamGeometry = new StreamGeometry(); - protected override Geometry DefiningGeometry => StreamGeometry; - - - #region 控件属性,所在的节点 - public static readonly DependencyProperty NodeProperty = - DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(ParamsArgControl), new PropertyMetadata(default(NodeModelBase))); - //public NodeModelBase NodeModel; - - /// - /// 所在的节点 - /// - public NodeModelBase MyNode - { - get { return (NodeModelBase)GetValue(NodeProperty); } - set { SetValue(NodeProperty, value); } - } - #endregion - - #region 控件属性,连接器类型 - public static readonly DependencyProperty ArgIndexProperty = - DependencyProperty.Register(nameof(ArgIndex), typeof(int), typeof(ParamsArgControl), new PropertyMetadata(default(int))); - - /// - /// 参数的索引 - /// - public int ArgIndex - { - get { return (int)GetValue(ArgIndexProperty); } - set { SetValue(ArgIndexProperty, value.ToString()); } - } - #endregion - - - /// - /// 控件重绘事件 - /// - /// - protected override void OnRender(DrawingContext drawingContext) - { - Brush brush = isMouseOver ? Brushes.Red : Brushes.Green; - double height = ActualHeight; - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - var circlePoint = new Point(circleCenterX, circleCenterY); - - // 圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - - drawingContext.DrawGeometry(brush, MyUIFunc.CreateAndFreezePen(), ellipse); - } - - - private bool isMouseOver; // 鼠标悬停状态 - - private Func AddOrRemoveParamsTask; // 增加或删除参数 - - public async void ParamsArg_OnMouseDown(object sender, MouseButtonEventArgs e) - { - await AddOrRemoveParamsTask.Invoke(); - } - - private void ParamsArgControl_MouseMove(object sender, MouseEventArgs e) - { - isMouseOver = true; - if (cancellationTokenSource.IsCancellationRequested) { - cancellationTokenSource = new CancellationTokenSource(); - Task.Run(async () => - { - await Task.Delay(380); - - }, cancellationTokenSource.Token).ContinueWith((t) => - { - // 如果焦点仍在控件上时,则改变点击事件 - if (isMouseOver) - { - AddOrRemoveParamsTask = RemoveAsync; - this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘 - - } - }); - } - - } - private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); - - - private void ParamsArgControl_MouseLeave(object sender, MouseEventArgs e) - { - isMouseOver = false; - AddOrRemoveParamsTask = AddAsync; // 鼠标焦点离开时恢复点击事件 - cancellationTokenSource?.Cancel(); - this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘 - - } - - - private async Task AddAsync() - { - await this.MyNode.Env.ChangeParameter(MyNode.Guid, true, ArgIndex); - } - private async Task RemoveAsync() - { - await this.MyNode.Env.ChangeParameter(MyNode.Guid, false, ArgIndex); - } - - } - - - - public abstract class JunctionControlBase : Shape - { - protected JunctionControlBase() - { - this.Width = 25; - this.Height = 20; - this.MouseDown += JunctionControlBase_MouseDown; - this.MouseMove += JunctionControlBase_MouseMove; - this.MouseLeave += JunctionControlBase_MouseLeave; ; - } - - - #region 控件属性,所在的节点 - public static readonly DependencyProperty NodeProperty = - DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase))); - //public NodeModelBase NodeModel; - - /// - /// 所在的节点 - /// - public NodeModelBase MyNode - { - get { return (NodeModelBase)GetValue(NodeProperty); } - set { SetValue(NodeProperty, value); } - } - #endregion - - #region 控件属性,连接器类型 - public static readonly DependencyProperty JunctionTypeProperty = - DependencyProperty.Register(nameof(JunctionType), typeof(string), typeof(JunctionControlBase), new PropertyMetadata(default(string))); - - /// - /// 控制点类型 - /// - public JunctionType JunctionType - { - get { return EnumHelper.ConvertEnum(GetValue(JunctionTypeProperty).ToString()); } - set { SetValue(JunctionTypeProperty, value.ToString()); } - } - #endregion - - protected readonly StreamGeometry StreamGeometry = new StreamGeometry(); - protected override Geometry DefiningGeometry => StreamGeometry; - - /// - /// 重绘方法 - /// - /// - public abstract void Render(DrawingContext drawingContext); - /// - /// 中心点 - /// - public abstract Point MyCenterPoint { get; } - - - - /// - /// 禁止连接 - /// - private bool IsConnectionDisable; - - /// - /// 处理鼠标悬停状态 - /// - private bool _isMouseOver; - public bool IsMouseOver - { - get => _isMouseOver; - set - { - if(_isMouseOver != value) - { - GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this; - _isMouseOver = value; - InvalidateVisual(); - } - - } - } - - /// - /// 控件重绘事件 - /// - /// - protected override void OnRender(DrawingContext drawingContext) - { - Render(drawingContext); - } - - /// - /// 获取背景颜色 - /// - /// - protected Brush GetBackgrounp() - { - var myData = GlobalJunctionData.MyGlobalConnectingData; - if(!myData.IsCreateing) - { - return Brushes.Transparent; - } - if (IsMouseOver) - { - if (myData.IsCanConnected) - { - if (myData.Type == JunctionOfConnectionType.Invoke) - { - return myData.ConnectionInvokeType.ToLineColor(); - } - else - { - return myData.ConnectionArgSourceType.ToLineColor(); - } - } - else - { - return Brushes.Red; - } - } - else - { - return Brushes.Transparent; - } - } - - private object lockObj = new object(); - - /// - /// 控件获得鼠标焦点事件 - /// - /// - /// - private void JunctionControlBase_MouseMove(object sender, MouseEventArgs e) - { - //if (!GlobalJunctionData.MyGlobalConnectingData.IsCreateing) return; - - //if (IsMouseOver) return; - IsMouseOver = true; - - //this.InvalidateVisual(); - } - - /// - /// 控件失去鼠标焦点事件 - /// - /// - /// - private void JunctionControlBase_MouseLeave(object sender, MouseEventArgs e) - { - IsMouseOver = false; - e.Handled = true; - - } - - - /// - /// 在碰撞点上按下鼠标控件开始进行移动 - /// - /// - /// - protected void JunctionControlBase_MouseDown(object sender, MouseButtonEventArgs e) - { - if (e.LeftButton == MouseButtonState.Pressed) - { - var canvas = MainWindow.GetParentOfType(this); - if (canvas != null) - { - var myData = GlobalJunctionData.MyGlobalConnectingData; - myData.Reset(); - myData.IsCreateing = true; // 表示开始连接 - myData.StartJunction = this; - myData.CurrentJunction = this; - myData.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas); - - var junctionOfConnectionType = this.JunctionType.ToConnectyionType(); - ConnectionLineShape bezierLine; // 类别 - Brush brushColor; // 临时线的颜色 - if (junctionOfConnectionType == JunctionOfConnectionType.Invoke) - { - brushColor = ConnectionInvokeType.IsSucceed.ToLineColor(); - } - else if(junctionOfConnectionType == JunctionOfConnectionType.Arg) - { - brushColor = ConnectionArgSourceType.GetOtherNodeData.ToLineColor(); - } - else - { - return; - } - bezierLine = new ConnectionLineShape(LineType.Bezier, - myData.StartPoint, - myData.StartPoint, - brushColor, - isTop: true); // 绘制临时的线 - - Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线 - myData.MyLine = new MyLine(canvas, bezierLine); - } - } - e.Handled = true; - } - - private Point GetStartPoint() - { - return new Point(this.ActualWidth / 2, this.ActualHeight / 2); // 起始节点选择右侧边缘中心 - } - - - - - - } - - - - - - - -} diff --git a/Workbench/Node/Junction/JunctionData.cs b/Workbench/Node/Junction/JunctionData.cs deleted file mode 100644 index ceb3048..0000000 --- a/Workbench/Node/Junction/JunctionData.cs +++ /dev/null @@ -1,161 +0,0 @@ -using Serein.Library; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -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, ConnectionLineShape line) - { - Canvas = canvas; - Line = line; - canvas?.Children.Add(line); - } - - public Canvas Canvas { get; set; } - public ConnectionLineShape Line { get; set; } - - public void Remove() - { - Canvas?.Children.Remove(Line); - } - } - - public class ConnectingData - { - - /// - /// 是否正在创建连线 - /// - public bool IsCreateing { get; set; } - /// - /// 起始控制点 - /// - public JunctionControlBase StartJunction { get; set; } - /// - /// 当前的控制点 - /// - public JunctionControlBase CurrentJunction { get; set; } - /// - /// 开始坐标 - /// - public Point StartPoint { get; set; } - /// - /// 线条样式 - /// - public MyLine MyLine { get; set; } - - /// - /// 线条类别(方法调用) - /// - public ConnectionInvokeType ConnectionInvokeType { get; set; } = ConnectionInvokeType.IsSucceed; - /// - /// 线条类别(参数传递) - /// - public ConnectionArgSourceType ConnectionArgSourceType { get; set; } = ConnectionArgSourceType.GetOtherNodeData; - - /// - /// 判断当前连接类型 - /// - public JunctionOfConnectionType Type => StartJunction.JunctionType.ToConnectyionType(); - - - /// - /// 是否允许连接 - /// - - public bool IsCanConnected { get - { - - if(StartJunction is null - || CurrentJunction is null - ) - { - return false; - } - - - if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode) - && StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType)) - { - return true; - } - else - { - return false; - } - } - } - - /// - /// 更新临时的连接线 - /// - /// - public void UpdatePoint(Point point) - { - if (StartJunction is null - || CurrentJunction is null - ) - { - return; - } - if (StartJunction.JunctionType == Library.JunctionType.Execute - || StartJunction.JunctionType == Library.JunctionType.ArgData) - { - MyLine.Line.UpdateStartPoints(point); - } - else - { - MyLine.Line.UpdateEndPoints(point); - - } - } - - /// - /// 重置 - /// - public void Reset() - { - IsCreateing = false; - StartJunction = null; - CurrentJunction = null; - MyLine?.Remove(); - ConnectionInvokeType = ConnectionInvokeType.IsSucceed; - ConnectionArgSourceType = ConnectionArgSourceType.GetOtherNodeData; - } - - - - } - - public static class GlobalJunctionData - { - //private static ConnectingData? myGlobalData; - //private static object _lockObj = new object(); - - /// - /// 创建节点之间控制点的连接行为 - /// - public static ConnectingData MyGlobalConnectingData { get; } = new ConnectingData(); - - /// - /// 删除连接视觉效果 - /// - public static void OK() - { - MyGlobalConnectingData.Reset(); - } - } - #endregion -} diff --git a/Workbench/Node/Junction/NodeJunctionViewBase.cs b/Workbench/Node/Junction/NodeJunctionViewBase.cs deleted file mode 100644 index 92e6a59..0000000 --- a/Workbench/Node/Junction/NodeJunctionViewBase.cs +++ /dev/null @@ -1,237 +0,0 @@ -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; - } - - /// - /// 每个连接器都有一个唯一标识符(Guid),用于标识连接器。 - /// - 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)); - - /// - /// 连接器当前的连接数,表示有多少条 NodeLink 连接到此连接器。该属性为只读。 - /// - 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; - - /// - /// 布尔值,指示此连接器是否有任何连接。 - /// - 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; - - /// - /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 - /// - 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)); - - /// - /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 - /// - 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)); - - /// - /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 - /// - 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)); - - /// - /// 指示该连接器是否可以与其他连接器进行连接。 - /// - 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(); - /// - /// 该连接器的当前坐标(位置)。 - /// - public Point Position - { - get => _Position; - set => UpdatePosition(value); - } - - /// - /// (重要数据)表示连接器所属的节点。 - /// - public NodeModelBase NodeModel { get; private set; } = null; - - /// - /// 该连接器所连接的所有 NodeLink 的集合。 - /// - public IEnumerable NodeLinks => _NodeLinks; - List _NodeLinks = new List(); - - protected abstract FrameworkElement ConnectorControl { get; } - TranslateTransform _Translate = new TranslateTransform(); - void UpdatePosition(Point pos) - { - _Position = pos; - _Translate.X = _Position.X; - _Translate.Y = _Position.Y; - - InvalidateVisual(); - } - - /// - /// 将 NodeLink 添加到连接器,并更新 ConnectedCount 和 IsConnected。 - /// - /// - public void Connect(ConnectionControl nodeLink) - { - _NodeLinks.Add(nodeLink); - ConnectedCount = _NodeLinks.Count; - IsConnected = ConnectedCount > 0; - } - - /// - /// 断开与某个 NodeLink 的连接,更新连接状态。 - /// - /// - public void Disconnect(ConnectionControl nodeLink) - { - _NodeLinks.Remove(nodeLink); - ConnectedCount = _NodeLinks.Count; - IsConnected = ConnectedCount > 0; - } - - /// - /// 获取连接器相对于指定 Canvas 的位置。 - /// - /// - /// - /// - /// - 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)); - } - - /// - /// 更新与此连接器相连的所有 NodeLink 的位置。这个方法是抽象的,要求子类实现。 - /// - /// - public abstract void UpdateLinkPosition(Canvas canvas); - - /// - /// 用于检查此连接器是否可以与另一个连接器相连接,要求子类实现。 - /// - /// - /// - public abstract bool CanConnectTo(NodeJunctionViewBase connector); - - /// - /// 释放连接器相关的资源,包括样式、绑定和已连接的 NodeLink - /// - 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(); - } - } - - } -} diff --git a/Workbench/Node/Junction/View/ArgJunctionControl.cs b/Workbench/Node/Junction/View/ArgJunctionControl.cs deleted file mode 100644 index 6ef6927..0000000 --- a/Workbench/Node/Junction/View/ArgJunctionControl.cs +++ /dev/null @@ -1,74 +0,0 @@ -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; - this.InvalidateVisual(); - } - - #region 控件属性,对应的参数 - public static readonly DependencyProperty ArgIndexProperty = - DependencyProperty.Register("ArgIndex", typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int))); - - /// - /// 所在的节点 - /// - public int ArgIndex - { - get { return (int)GetValue(ArgIndexProperty); } - set { SetValue(ArgIndexProperty, value); } - } - - - #endregion - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - - - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - var background = GetBackgrounp(); - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - var circlePoint = new Point(circleCenterX, circleCenterY); - _myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标 - - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - } - } - - -} diff --git a/Workbench/Node/Junction/View/ExecuteJunctionControl.cs b/Workbench/Node/Junction/View/ExecuteJunctionControl.cs deleted file mode 100644 index 9247df1..0000000 --- a/Workbench/Node/Junction/View/ExecuteJunctionControl.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; -using Serein.Library; - -namespace Serein.Workbench.Node.View -{ - public class ExecuteJunctionControl : JunctionControlBase - { - - - - public ExecuteJunctionControl() - { - base.JunctionType = JunctionType.Execute; - this.InvalidateVisual(); - - } - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - var background = GetBackgrounp(); - // 绘制边框 - //var borderBrush = new SolidColorBrush(Colors.Black); - //var borderThickness = 1.0; - //var borderRect = new Rect(0, 0, width, height); - //drawingContext.DrawRectangle(null, new Pen(borderBrush, borderThickness), borderRect); - - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent,null, connectorRect); - //drawingContext.DrawRectangle(Brushes.Transparent, new Pen(background,2), connectorRect); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - _myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标 - - var circlePoint = new Point(circleCenterX, circleCenterY); - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - - - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - - - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - - // 绘制标签 - //var formattedText = new FormattedText( - // "执行", - // System.Globalization.CultureInfo.CurrentCulture, - // FlowDirection.LeftToRight, - // new Typeface("Segoe UI"), - // 12, - // Brushes.Black, - // VisualTreeHelper.GetDpi(this).PixelsPerDip); - //drawingContext.DrawText(formattedText, new Point(18,1)); - } - } - - -} diff --git a/Workbench/Node/Junction/View/NextStepJunctionControl.cs b/Workbench/Node/Junction/View/NextStepJunctionControl.cs deleted file mode 100644 index 7c5bde9..0000000 --- a/Workbench/Node/Junction/View/NextStepJunctionControl.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Windows; -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; - this.InvalidateVisual(); - } - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - var background = GetBackgrounp(); - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - _myCenterPoint = new Point(circleCenterX - connectorSize / 2, circleCenterY); // 中心坐标 - - var circlePoint = new Point(circleCenterX, circleCenterY); - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - // 绘制连接器的圆形部分 - //var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - } - } -} diff --git a/Workbench/Node/Junction/View/ResultJunctionControl.cs b/Workbench/Node/Junction/View/ResultJunctionControl.cs deleted file mode 100644 index aaad0d3..0000000 --- a/Workbench/Node/Junction/View/ResultJunctionControl.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Windows; -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; - this.InvalidateVisual(); - } - private Point _myCenterPoint; - public override Point MyCenterPoint { get => _myCenterPoint; } - - public override void Render(DrawingContext drawingContext) - { - double width = ActualWidth; - double height = ActualHeight; - - // 输入连接器的背景 - var connectorRect = new Rect(0, 0, width, height); - drawingContext.DrawRectangle(Brushes.Transparent, null, connectorRect); - - var background = GetBackgrounp(); - - // 定义圆形的大小和位置 - double connectorSize = 10; // 连接器的大小 - double circleCenterX = 8; // 圆心 X 坐标 - double circleCenterY = height / 2; // 圆心 Y 坐标 - var circlePoint = new Point(circleCenterX, circleCenterY); - - _myCenterPoint = new Point(circleCenterX - connectorSize / 2 , circleCenterY); // 中心坐标 - - // 绘制连接器的圆形部分 - var ellipse = new EllipseGeometry(circlePoint, connectorSize / 2, connectorSize / 2); - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), ellipse); - - // 定义三角形的间距 - double triangleOffsetX = 4; // 三角形与圆形的间距 - double triangleCenterX = circleCenterX + connectorSize / 2 + triangleOffsetX; // 三角形中心 X 坐标 - double triangleCenterY = circleCenterY; // 三角形中心 Y 坐标 - - // 绘制三角形 - var pathGeometry = new StreamGeometry(); - using (var context = pathGeometry.Open()) - { - context.BeginFigure(new Point(triangleCenterX, triangleCenterY - 4.5), true, true); - context.LineTo(new Point(triangleCenterX + 5, triangleCenterY), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY + 4.5), true, false); - context.LineTo(new Point(triangleCenterX, triangleCenterY - 4.5), true, false); - } - drawingContext.DrawGeometry(background, MyUIFunc.CreateAndFreezePen(), pathGeometry); - } - } -} diff --git a/Workbench/Node/NodeControlBase.cs b/Workbench/Node/NodeControlBase.cs deleted file mode 100644 index 2487cfb..0000000 --- a/Workbench/Node/NodeControlBase.cs +++ /dev/null @@ -1,198 +0,0 @@ -using Serein.Library; -using Serein.Library.Api; -using Serein.Workbench.Node.ViewModel; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Media; - -namespace Serein.Workbench.Node.View -{ - - /// - /// 节点控件基类(控件) - /// - public abstract class NodeControlBase : UserControl, IDynamicFlowNode - { - /// - /// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能) - /// - public Canvas NodeCanvas { get; set; } - - private INodeContainerControl nodeContainerControl; - /// - /// 如果该节点放置在了某个容器节点,就会记录这个容器节点 - /// - private INodeContainerControl NodeContainerControl { get; } - - /// - /// 记录与该节点控件有关的所有连接 - /// - private readonly List connectionControls = new List(); - - public NodeControlViewModelBase ViewModel { get; set; } - - - protected NodeControlBase() - { - this.Background = Brushes.Transparent; - } - - protected NodeControlBase(NodeControlViewModelBase viewModelBase) - { - ViewModel = viewModelBase; - this.Background = Brushes.Transparent; - this.DataContext = viewModelBase; - SetBinding(); - } - - /// - /// 放置在某个节点容器中 - /// - public void PlaceToContainer(INodeContainerControl nodeContainerControl) - { - this.nodeContainerControl = nodeContainerControl; - NodeCanvas.Children.Remove(this); // 临时从画布上移除 - var result = nodeContainerControl.PlaceNode(this); - if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来 - { - NodeCanvas.Children.Add(this); // 从画布上移除 - - } - } - - /// - /// 从某个节点容器取出 - /// - public void TakeOutContainer() - { - var result = nodeContainerControl.TakeOutNode(this); // 从控件取出 - if (result) // 移除成功时才添加到画布上 - { - NodeCanvas.Children.Add(this); // 重新添加到画布上 - if (nodeContainerControl is NodeControlBase containerControl) - { - this.ViewModel.NodeModel.Position.X = containerControl.ViewModel.NodeModel.Position.X + containerControl.Width + 10; - this.ViewModel.NodeModel.Position.Y = containerControl.ViewModel.NodeModel.Position.Y; - } - } - - } - - /// - /// 添加与该节点有关的连接后,记录下来 - /// - /// - public void AddCnnection(ConnectionControl connection) - { - connectionControls.Add(connection); - } - - /// - /// 删除了连接之后,还需要从节点中的记录移除 - /// - /// - public void RemoveConnection(ConnectionControl connection) - { - connectionControls.Remove(connection); - connection.Remote(); - } - - /// - /// 删除所有连接 - /// - public void RemoveAllConection() - { - foreach (var connection in this.connectionControls) - { - connection.Remote(); - } - } - - /// - /// 更新与该节点有关的数据 - /// - public void UpdateLocationConnections() - { - foreach (var connection in this.connectionControls) - { - connection.RefreshLine(); // 主动更新连线位置 - } - } - - - /// - /// 设置绑定: - /// Canvas.X and Y : 画布位置 - /// - public void SetBinding() - { - // 绑定 Canvas.Left - Binding leftBinding = new Binding("X") - { - Source = ViewModel.NodeModel.Position, // 如果 X 属性在当前 DataContext 中 - Mode = BindingMode.TwoWay - }; - BindingOperations.SetBinding(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); - } - - /// - /// 穿透视觉树获取指定类型的第一个元素 - /// - /// - /// - /// - protected T FindVisualChild(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(child); - if (childOfChild != null) - { - return childOfChild; - } - } - return null; - } - - - - } - - - - - //public class FLowNodeObObservableCollection : ObservableCollection - //{ - - // public void AddRange(IEnumerable items) - // { - // foreach (var item in items) - // { - // this.Items.Add(item); - // } - // OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); - // } - //} -} - - - - - - diff --git a/Workbench/Node/RelayCommand.cs b/Workbench/Node/RelayCommand.cs deleted file mode 100644 index a19b531..0000000 --- a/Workbench/Node/RelayCommand.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Windows.Input; - -namespace Serein.Workbench.Node -{ - - public class RelayCommand : ICommand - { - private readonly Action _execute; - private readonly Func _canExecute; - - public RelayCommand(Action execute, Func canExecute = null) - { - _execute = execute; - _canExecute = canExecute; - } - - public event EventHandler CanExecuteChanged; - - public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter); - - public void Execute(object parameter) => _execute(parameter); - - public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } - -} diff --git a/Workbench/Node/View/ConnectionControl.cs b/Workbench/Node/View/ConnectionControl.cs deleted file mode 100644 index e41637d..0000000 --- a/Workbench/Node/View/ConnectionControl.cs +++ /dev/null @@ -1,297 +0,0 @@ -using Serein.Library; -using Serein.Library.Api; -using Serein.Workbench.Extension; -using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; -using Color = System.Windows.Media.Color; -using ColorConverter = System.Windows.Media.ColorConverter; -using Point = System.Windows.Point; - -namespace Serein.Workbench.Node.View -{ - #region 连接点相关代码 - - - - public class ConnectionModelBase - { - /// - /// 起始节点 - /// - public NodeModelBase StartNode { get; set; } - /// - /// 目标节点 - /// - public NodeModelBase EndNode { get; set; } - - /// - /// 来源于起始节点的(控制点)类型 - /// - public JunctionType JoinTypeOfStart { get; set; } - - /// - /// 连接到目标节点的(控制点)类型 - /// - public JunctionType JoinTypeOfEnd { get; set; } - - /// - /// 连接类型 - /// - public ConnectionInvokeType Type { get; set; } - } - - - public interface IJunctionNode - { - string BoundNodeGuid { get; } - } - - /// - /// 连接点 - /// - public class JunctionNode : IJunctionNode - { - /// - /// 连接点类型 - /// - public JunctionType JunctionType { get; } - /// - /// 对应的视图对象 - /// - public NodeModelBase NodeModel { get; set; } - /// - /// - /// - public string BoundNodeGuid { get => NodeModel.Guid; } - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #endregion - - /// - /// 连接控件,表示控件的连接关系 - /// - public class ConnectionControl - { - /// - /// 所在的画布 - /// - public Canvas Canvas { get; } - - /// - /// 调用方法类型,连接类型 - /// - public ConnectionInvokeType InvokeType { get; } - - /// - /// 目标节点控制点 - /// - private INodeJunction EndNode; - - /// - /// 获取参数类型,第几个参数 - /// - public int ArgIndex { get; set; } = -1; - - /// - /// 参数来源(决定了连接线的样式) - /// - public ConnectionArgSourceType ArgSourceType { get; set; } - - /// - /// 起始控制点 - /// - public JunctionControlBase Start { get; set; } - - /// - /// 目标控制点 - /// - public JunctionControlBase End { get; set; } - - /// - /// 连接线 - /// - private ConnectionLineShape BezierLine; - - - - private LineType LineType; - - /// - /// 关于调用 - /// - /// - /// - public ConnectionControl(Canvas Canvas, - ConnectionInvokeType invokeType, - JunctionControlBase Start, - JunctionControlBase End) - { - this.LineType = LineType.Bezier; - this.Canvas = Canvas; - this.InvokeType = invokeType; - this.Start = Start; - this.End = End; - InitElementPoint(); - } - - /// - /// 关于入参 - /// - /// - /// - public ConnectionControl(LineType LineType, - Canvas Canvas, - int argIndex, - ConnectionArgSourceType argSourceType, - JunctionControlBase Start, - JunctionControlBase End, - INodeJunction nodeJunction) - { - this.LineType = LineType; - this.Canvas = Canvas; - this.ArgIndex = argIndex; - this.ArgSourceType = argSourceType; - this.Start = Start; - this.End = End; - this.EndNode = nodeJunction; - InitElementPoint(); - } - - /// - /// 绘制 - /// - public void InitElementPoint() - { - leftCenterOfEndLocation = Start.MyCenterPoint; - rightCenterOfStartLocation = End.MyCenterPoint; - - (Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End); - var connectionType = Start.JunctionType.ToConnectyionType(); - bool isDotted; - Brush brush; - if(connectionType == JunctionOfConnectionType.Invoke) - { - brush = InvokeType.ToLineColor(); - isDotted = false; - } - else - { - brush = ArgSourceType.ToLineColor(); - isDotted = true; // 如果为参数,则绘制虚线 - } - BezierLine = new ConnectionLineShape(LineType, startPoint, endPoint, brush, isDotted); - Grid.SetZIndex(BezierLine, -9999999); // 置底 - Canvas.Children.Add(BezierLine); - - ConfigureLineContextMenu(); //配置右键菜单 - } - - - /// - /// 配置连接曲线的右键菜单 - /// - private void ConfigureLineContextMenu() - { - var contextMenu = new ContextMenu(); - contextMenu.Items.Add(MainWindow.CreateMenuItem("删除连线", (s, e) => Remote())); - contextMenu.Items.Add(MainWindow.CreateMenuItem("于父节点调用顺序中置顶", (s, e) => Topping())); - BezierLine.ContextMenu = contextMenu; - } - - - /// - /// 删除该连线 - /// - public void Remote() - { - Canvas.Children.Remove(BezierLine); - var env = Start.MyNode.Env; - if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) - { - env.RemoveConnectInvokeAsync(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); - } - else if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Arg) - { - env.RemoveConnectArgSourceAsync(Start.MyNode.Guid, End.MyNode.Guid, ArgIndex) ; - } - } - - /// - /// 置顶调用关系 - /// - public void Topping() - { - var env = Start.MyNode.Env; - if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) - { - env.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); - } - } - - /// - /// 重新绘制 - /// - public void RefreshLine() - { - if(ArgIndex > -1) - { - End = EndNode.GetJunctionOfArgData(ArgIndex) ?? End; - } - (Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End); - BezierLine.UpdatePoints(startPoint, endPoint); - } - - - private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心 - private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心 - /// - /// 刷新坐标 - /// - - private (Point startPoint, Point endPoint) RefreshPoint(Canvas canvas, FrameworkElement startElement, FrameworkElement endElement) - { - var startPoint = startElement.TranslatePoint(rightCenterOfStartLocation, canvas); // 获取起始节点的中心位置 - var endPoint = endElement.TranslatePoint(leftCenterOfEndLocation, canvas); // 计算终点位置 - return (startPoint, endPoint); - } - } - - - - - - - - -} diff --git a/Workbench/Node/View/GlobalDataControl.xaml b/Workbench/Node/View/GlobalDataControl.xaml deleted file mode 100644 index 56b23c3..0000000 --- a/Workbench/Node/View/GlobalDataControl.xaml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Workbench/Node/View/GlobalDataControl.xaml.cs b/Workbench/Node/View/GlobalDataControl.xaml.cs deleted file mode 100644 index f3f4bf3..0000000 --- a/Workbench/Node/View/GlobalDataControl.xaml.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.ViewModel; -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.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace Serein.Workbench.Node.View -{ - /// - /// UserControl1.xaml 的交互逻辑 - /// - public partial class GlobalDataControl : NodeControlBase, INodeJunction, INodeContainerControl - { - public GlobalDataControl() : base() - { - // 窗体初始化需要 - base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(null)); - DataContext = ViewModel; - InitializeComponent(); - } - - public GlobalDataControl(GlobalDataNodeControlViewModel viewModel) : base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - } - - - /// - /// 入参控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; - - /// - /// 下一个调用方法控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; - - /// - /// 返回值控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ReturnDataJunction => throw new NotImplementedException(); - - /// - /// 方法入参控制点(可能有,可能没) - /// - JunctionControlBase[] INodeJunction.ArgDataJunction => throw new NotImplementedException(); - - - public bool PlaceNode(NodeControlBase nodeControl) - { - if (GlobalDataPanel.Children.Contains(nodeControl)) - { - return false; - } - GlobalDataPanel.Children.Add(nodeControl); - return true; - } - - public bool TakeOutNode(NodeControlBase nodeControl) - { - if (!GlobalDataPanel.Children.Contains(nodeControl)) - { - return false; - } - GlobalDataPanel.Children.Remove(nodeControl); - return true; - } - - public void TakeOutAll() - { - GlobalDataPanel.Children.Clear(); - } - - } -} diff --git a/Workbench/Node/View/ScriptNodeControl.xaml b/Workbench/Node/View/ScriptNodeControl.xaml deleted file mode 100644 index b7d0808..0000000 --- a/Workbench/Node/View/ScriptNodeControl.xaml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Workbench/Node/View/ScriptNodeControl.xaml.cs b/Workbench/Node/View/ScriptNodeControl.xaml.cs deleted file mode 100644 index f16decf..0000000 --- a/Workbench/Node/View/ScriptNodeControl.xaml.cs +++ /dev/null @@ -1,162 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.ViewModel; -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.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using System.Windows.Threading; - -namespace Serein.Workbench.Node.View -{ - /// - /// ScriptNodeControl.xaml 的交互逻辑 - /// - public partial class ScriptNodeControl : NodeControlBase , INodeJunction - { - private ScriptNodeControlViewModel viewModel => (ScriptNodeControlViewModel)ViewModel; - private DispatcherTimer _debounceTimer; // 用于延迟更新 - private bool _isUpdating = false; // 防止重复更新 - - public ScriptNodeControl() - { - InitializeComponent(); - } - public ScriptNodeControl(ScriptNodeControlViewModel viewModel) : base(viewModel) - { - DataContext = viewModel; - InitializeComponent(); - -#if false - // 初始化定时器 - _debounceTimer = new DispatcherTimer(); - _debounceTimer.Interval = TimeSpan.FromMilliseconds(500); // 停止输入 500ms 后更新 - _debounceTimer.Tick += DebounceTimer_Tick; -#endif - } - - - - - /// - /// 入参控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl; - - /// - /// 下一个调用方法控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.NextStepJunction => this.NextStepJunctionControl; - - /// - /// 返回值控制点(可能有,可能没) - /// - JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl; - - /// - /// 方法入参控制点(可能有,可能没) - /// - JunctionControlBase[] INodeJunction.ArgDataJunction - { - get - { - // 获取 MethodDetailsControl 实例 - var methodDetailsControl = this.MethodDetailsControl; - var itemsControl = FindVisualChild(methodDetailsControl); // 查找 ItemsControl - if (itemsControl != null) - { - var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length]; - var controls = new List(); - - for (int i = 0; i < itemsControl.Items.Count; i++) - { - var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement; - if (container != null) - { - var argControl = FindVisualChild(container); - if (argControl != null) - { - controls.Add(argControl); // 收集 ArgJunctionControl 实例 - } - } - } - return argDataJunction = controls.ToArray(); - } - else - { - return []; - } - } - - - } - - - - - - - - - - - - - -#if false - // 每次输入时重置定时器 - private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e) - { - _debounceTimer.Stop(); - _debounceTimer.Start(); - } - - // 定时器事件,用户停止输入后触发 - private async void DebounceTimer_Tick(object sender, EventArgs e) - { - _debounceTimer.Stop(); - - if (_isUpdating) - return; - - // 开始后台处理语法分析和高亮 - _isUpdating = true; - await Task.Run(() => HighlightKeywordsAsync(viewModel.Script)); - } - - // 异步执行语法高亮操作 - private async Task HighlightKeywordsAsync(string text) - { - if (string.IsNullOrEmpty(text)) - { - return; - } - // 模拟语法分析和高亮(可以替换为实际逻辑) - var highlightedText = text; - - // 在 UI 线程中更新 RichTextBox 的内容 - await Dispatcher.BeginInvoke(() => - { - var range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); - range.Text = highlightedText; - }); - - _isUpdating = false; - } - -#endif - - - - - } -} diff --git a/Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs b/Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs deleted file mode 100644 index d9aaa08..0000000 --- a/Workbench/Node/ViewModel/ExpOpNodeControlViewModel.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.View; - -namespace Serein.Workbench.Node.ViewModel -{ - public class ExpOpNodeControlViewModel: NodeControlViewModelBase - { - public new SingleExpOpNode NodeModel { get; } - - //public string Expression - //{ - // get => node.Expression; - // set - // { - // node.Expression = value; - // OnPropertyChanged(); - // } - //} - - - public ExpOpNodeControlViewModel(SingleExpOpNode nodeModel) : base(nodeModel) - { - this.NodeModel = nodeModel; - } - } -} diff --git a/Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs b/Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs deleted file mode 100644 index a396cba..0000000 --- a/Workbench/Node/ViewModel/GlobalDataNodeControlViewModel.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Serein.Library; -using Serein.NodeFlow.Model; -using Serein.Workbench.Node.View; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; - -namespace Serein.Workbench.Node.ViewModel -{ - public class GlobalDataNodeControlViewModel : NodeControlViewModelBase - { - private SingleGlobalDataNode NodeModel => (SingleGlobalDataNode)base.NodeModel; - - /// - /// 复制全局数据表达式 - /// - public ICommand CommandCopyDataExp { get; } - - /// - /// 刷新数据 - /// - public ICommand CommandRefreshData { get; } - - - public GlobalDataNodeControlViewModel(SingleGlobalDataNode node) : base(node) - { - CommandCopyDataExp = new RelayCommand( o => - { - string exp = NodeModel.KeyName; - string copyValue = $"@Get #{exp}#"; - Clipboard.SetDataObject(copyValue); - }); - } - - /// - /// 自定义参数值 - /// - public string? KeyName - { - get => NodeModel?.KeyName; - set { NodeModel.KeyName = value; OnPropertyChanged(); } - } - - - - } -} diff --git a/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs b/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs deleted file mode 100644 index 6b03113..0000000 --- a/Workbench/Node/ViewModel/ScriptNodeControlViewModel.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Serein.Library; -using Serein.Library.Core; -using Serein.Library.Utils; -using Serein.NodeFlow.Model; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; - -namespace Serein.Workbench.Node.ViewModel -{ - public class ScriptNodeControlViewModel : NodeControlViewModelBase - { - private SingleScriptNode NodeModel => (SingleScriptNode)base.NodeModel; - - public string? Script - { - get => NodeModel?.Script; - set { NodeModel.Script = value; OnPropertyChanged(); } - } - - - - public ScriptNodeControlViewModel(NodeModelBase nodeModel) : base(nodeModel) - { - CommandExecuting = new RelayCommand(async o => - { - try - { - var result = await NodeModel.ExecutingAsync(new DynamicContext(nodeModel.Env)); - SereinEnv.WriteLine(InfoType.INFO, result?.ToString()); - } - catch (Exception ex) - { - SereinEnv.WriteLine(InfoType.ERROR, ex.ToString()); - } - }); - - CommandLoadScript = new RelayCommand( o => - { - NodeModel.ReloadScript(); - }); - } - - - /// - /// 加载脚本代码 - /// - public ICommand CommandLoadScript{ get; } - - /// - /// 尝试执行 - /// - public ICommand CommandExecuting { get; } - - - - } -} diff --git a/Workbench/Properties/launchSettings.json b/Workbench/Properties/launchSettings.json deleted file mode 100644 index f8eb472..0000000 --- a/Workbench/Properties/launchSettings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "profiles": { - "Serein.Workbench": { - "commandName": "Project" - } - } -} \ No newline at end of file diff --git a/Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj b/Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj deleted file mode 100644 index 4810142..0000000 --- a/Workbench/Serein.Workbench_wjzi1sgn_wpftmp.csproj +++ /dev/null @@ -1,292 +0,0 @@ - - - Serein.Workbench - obj\Release\ - obj\ - D:\Project\C#\DynamicControl\SereinFlow\WorkBench\obj\ - <_TargetAssemblyProjectName>Serein.Workbench - Serein.Workbench - - - - WinExe - net8.0-windows - enable - enable - True - D:\Project\C#\DynamicControl\SereinFlow\.Output - MIT - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Workbench/Themes/BindableRichTextBox.cs b/Workbench/Themes/BindableRichTextBox.cs deleted file mode 100644 index f7c9d1e..0000000 --- a/Workbench/Themes/BindableRichTextBox.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows; - -namespace Serein.Workbench.Themes -{ - public partial class BindableRichTextBox : RichTextBox - { - public new FlowDocument Document - { - get { return (FlowDocument)GetValue(DocumentProperty); } - set { SetValue(DocumentProperty, value); } - } - // Using a DependencyProperty as the backing store for Document. This enables animation, styling, binding, etc... - public static readonly DependencyProperty DocumentProperty = - DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnDucumentChanged))); - private static void OnDucumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RichTextBox rtb = (RichTextBox)d; - rtb.Document = (FlowDocument)e.NewValue; - } - } -} diff --git a/Workbench/Tool/GuidReplacer.cs b/Workbench/Tool/GuidReplacer.cs deleted file mode 100644 index eb2cf77..0000000 --- a/Workbench/Tool/GuidReplacer.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Serein.Workbench.Tool -{ - /// - /// Guid替换工具类 - /// - public class GuidReplacer - { - private class TrieNode - { - public Dictionary Children = new(); - public string Replacement; // 替换后的值 - } - - private readonly TrieNode _root = new(); - - // 构建字典树 - public void AddReplacement(string guid, string replacement) - { - var current = _root; - foreach (var c in guid) - { - if (!current.Children.ContainsKey(c)) - { - current.Children[c] = new TrieNode(); - } - current = current.Children[c]; - } - current.Replacement = replacement; - } - - // 替换逻辑 - public string Replace(string input) - { - var result = new StringBuilder(); - var current = _root; - int i = 0; - - while (i < input.Length) - { - if (current.Children.ContainsKey(input[i])) - { - current = current.Children[input[i]]; - i++; - - if (current.Replacement != null) // 找到匹配 - { - result.Append(current.Replacement); - current = _root; // 回到根节点 - } - } - else - { - result.Append(input[i]); - current = _root; // 未匹配,回到根节点 - i++; - } - } - return result.ToString(); - } - } - -}