1. 重新设计了Generate项目及相关特性的命名,避免与其他类型混淆。

2. 补充了部分注释。
3. 修改了删除容器节点时,容器内子节点未正确删除的问题。
This commit is contained in:
fengjiayi
2025-07-30 21:15:07 +08:00
parent 93148b11a5
commit 152077e9b5
188 changed files with 2713 additions and 1406 deletions

View File

@@ -10,10 +10,10 @@ namespace Serein.Workbench.Avalonia.Api
/// <summary>
/* /// <summary>
/// 约束一个节点应该有哪些控制点
/// </summary>
/*public interface INodeJunction
public interface INodeJunction
{
/// <summary>
/// 方法执行入口控制点

View File

@@ -34,12 +34,12 @@ namespace Serein.Workbench
/// </summary>
public static UIContextOperation UIContextOperation => App.GetService<UIContextOperation>() ?? throw new NullReferenceException();
public static T GetService<T>() where T : class
internal static T GetService<T>() where T : class
{
return ServiceProvider?.GetService<T>() ?? throw new NullReferenceException();
}
public App()
internal App()
{
var collection = new ServiceCollection();
collection.AddWorkbenchServices();
@@ -84,20 +84,19 @@ namespace Serein.Workbench
obj.Id = 114514;*/
if (1 == 11)
{
#if false
var projectService = App.GetService<FlowProjectService>();
await Task.Delay(500);
string filePath;
filePath = @"F:\TempFile\flow\temp2\project.dnf";
projectService.LoadLocalProject(filePath);
}
#endif
}
#endif
private async void Application_Startup(object sender, StartupEventArgs e)
private void Application_Startup(object sender, StartupEventArgs e)
{
var projectService = App.GetService<FlowProjectService>();
if (e.Args.Length == 1)

View File

@@ -10,7 +10,7 @@ using System.Diagnostics;
namespace Serein.Workbench.Converters
{
public class BoolToVisibilityConverter : IValueConverter
internal class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -10,7 +10,7 @@ using System.Windows;
namespace Serein.Workbench.Converters
{
public class CountToVisibilityConverter : IValueConverter
internal class CountToVisibilityConverter : IValueConverter
{
public bool Inverse { get; set; } = false; // 可选:反转逻辑

View File

@@ -8,14 +8,17 @@ using System.Windows.Data;
namespace Serein.Workbench.Converters
{
public class EnumToBooleanConverter : IValueConverter
internal class EnumToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
return false;
return value.ToString().Equals(parameter.ToString(), StringComparison.InvariantCultureIgnoreCase);
var leftValue = value?.ToString();
var rightValue = value?.ToString();
return string.Equals(leftValue, rightValue, StringComparison.InvariantCultureIgnoreCase);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

View File

@@ -13,7 +13,7 @@ namespace Serein.Workbench.Converters
/// 根据bool类型控制可见性
/// </summary>
[ValueConversion(typeof(bool), typeof(Visibility))]
public class InvertableBooleanToVisibilityConverter : IValueConverter
internal class InvertableBooleanToVisibilityConverter : IValueConverter
{
enum Parameters
{

View File

@@ -8,7 +8,7 @@ using System.Windows.Data;
namespace Serein.Workbench.Converters
{
public class MethodDetailsSelectorConverter : IMultiValueConverter
internal class MethodDetailsSelectorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -5,7 +5,7 @@ namespace Serein.Workbench.Converters
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class RightThumbPositionConverter : IValueConverter
internal class RightThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
@@ -22,7 +22,7 @@ namespace Serein.Workbench.Converters
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class BottomThumbPositionConverter : IValueConverter
internal class BottomThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
@@ -39,7 +39,7 @@ namespace Serein.Workbench.Converters
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class VerticalCenterThumbPositionConverter : IValueConverter
internal class VerticalCenterThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
@@ -56,7 +56,7 @@ namespace Serein.Workbench.Converters
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class HorizontalCenterThumbPositionConverter : IValueConverter
internal class HorizontalCenterThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{

View File

@@ -8,7 +8,7 @@ namespace Serein.Workbench.Converters
/// <summary>
/// 根据控件类型切换颜色
/// </summary>
public class TypeToColorConverter : IValueConverter
internal class TypeToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{

View File

@@ -42,8 +42,12 @@ namespace Serein.Workbench.Customs
/// </summary>
public partial class FlowMethodInfoListBox : UserControl, System.ComponentModel.INotifyPropertyChanged
{
private object viewMethodInfo;
public object ViewMethodInfo
private object? viewMethodInfo;
/// <summary>
/// 当前选中的方法信息
/// </summary>
public object? ViewMethodInfo
{
get => viewMethodInfo;
set
@@ -56,27 +60,44 @@ namespace Serein.Workbench.Customs
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 属性改变事件用于通知绑定的UI更新
/// </summary>
public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// FlowMethodInfoListBox 的构造函数
/// </summary>
public FlowMethodInfoListBox()
{
InitializeComponent();
}
/// <summary>
/// 依赖属性,用于绑定方法信息列表
/// </summary>
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(nameof(ItemsSource), typeof(IEnumerable), typeof(FlowMethodInfoListBox), new PropertyMetadata(null));
/// <summary>
/// 获取或设置方法信息列表
/// </summary>
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public static readonly DependencyProperty BackgroundProperty =
/// <summary>
/// 依赖属性,用于设置背景颜色
/// </summary>
public new static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register(nameof(Background), typeof(Brush), typeof(FlowMethodInfoListBox), new PropertyMetadata(Brushes.Transparent));
public Brush Background
/// <summary>
/// 获取或设置背景颜色
/// </summary>
public new Brush Background
{
get => (Brush)GetValue(BackgroundProperty);
set => SetValue(BackgroundProperty, value);

View File

@@ -7,30 +7,65 @@ using System.Windows;
namespace Serein.Workbench.Extension
{
/// <summary>
/// 点(Point)和向量(Vector)的扩展方法
/// </summary>
public static class PointExtension
{
/// <summary>
/// 将两个点相加,返回一个新的点。
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static Point Add(this Point a, Point b)
{
return new Point(a.X + b.X, a.Y + b.Y);
}
/// <summary>
/// 将两个点相减,返回一个新的点。
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static Point Sub(this Point a, Point b)
{
return new Point(a.X - b.X, a.Y - b.Y);
}
/// <summary>
/// 将点转换为向量。
/// </summary>
/// <param name="me"></param>
/// <returns></returns>
public static Vector ToVector(this Point me)
{
return new Vector(me.X, me.Y);
}
}
/// <summary>
/// 向量(Vector)的扩展方法
/// </summary>
public static class VectorExtension
{
/// <summary>
/// 计算两个向量的点积。
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static double DotProduct(this Vector a, Vector b)
{
return a.X * b.X + a.Y * b.Y;
}
/// <summary>
/// 计算两个向量的叉积。
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
public static Vector NormalizeTo(this Vector v)
{
var temp = v;

View File

@@ -1,16 +1,13 @@
using System.Windows;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using Timer = System.Timers.Timer;
namespace Serein.Workbench
{
/// <summary>
/// DebugWindow.xaml 的交互逻辑
/// </summary>
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
/// <summary>
/// LogWindow.xaml 的交互逻辑
@@ -18,6 +15,10 @@ namespace Serein.Workbench
public partial class LogWindow : Window
{
private static LogWindow instance = new LogWindow();
/// <summary>
/// 获取日志窗口的单例实例
/// </summary>
public static LogWindow Instance => instance;
@@ -29,6 +30,9 @@ namespace Serein.Workbench
private int flushThreshold = 5; // 设置日志刷新阈值
private const int maxFlushSize = 1000; // 每次最大刷新字符数
/// <summary>
/// 日志窗口构造函数,初始化组件和定时器
/// </summary>
public LogWindow()
{
InitializeComponent();

View File

@@ -15,30 +15,13 @@ using System.Xml.Linq;
namespace Serein.Workbench.Models
{
/// <summary>
/// FlowEditorTabModel 类表示一个流程编辑器的标签模型。
/// </summary>
public partial class FlowEditorTabModel : ObservableObject
{
/// <summary>
/// tab 名称
/// </summary>
/* public string Name
{
get
{
var vm = (FlowCanvasViewModel)Content.DataContext;
return vm.Model.Name ?? "null";
}
set
{
var vm = (FlowCanvasViewModel)Content.DataContext;
vm.Model.Name = value;
OnPropertyChanged(nameof(Name));
}
}
*/
[ObservableProperty]
private FlowCanvasDetails _model;
private FlowCanvasDetails? _model;
/// <summary>
@@ -57,8 +40,12 @@ namespace Serein.Workbench.Models
/// tab对应的控件
/// </summary>
[ObservableProperty]
private FlowCanvasView content;
private FlowCanvasView? content;
/// <summary>
/// FlowEditorTabModel 构造函数
/// </summary>
/// <param name="content"></param>
public FlowEditorTabModel(FlowCanvasView content)
{

View File

@@ -14,7 +14,7 @@ namespace Serein.Workbench.Node
/// <summary>
/// 约束一个节点应该有哪些控制点
/// </summary>
public interface INodeJunction
internal interface INodeJunction
{
/// <summary>
/// 方法执行入口控制点

View File

@@ -35,7 +35,7 @@ namespace Serein.Workbench.Node.View
/// </summary>
public class ConnectionLineShape : Shape
{
private readonly double strokeThickness;
//private readonly double strokeThickness;
private readonly LineType lineType;
@@ -47,6 +47,7 @@ namespace Serein.Workbench.Node.View
/// <param name="end">结束坐标</param>
/// <param name="brush">颜色</param>
/// <param name="isDotted">是否为虚线</param>
/// <param name="isTop">元素是否在画布上置顶</param>
public ConnectionLineShape(LineType lineType,
Point start,
Point end,
@@ -58,7 +59,7 @@ namespace Serein.Workbench.Node.View
this.brush = brush;
startPoint = start;
endPoint = end;
this.strokeThickness = 4;
//this.strokeThickness = 4;
InitElementPoint(isDotted, isTop);
_ = Task.Run(async () =>
@@ -72,6 +73,11 @@ namespace Serein.Workbench.Node.View
}
/// <summary>
/// 初始化连接线元素点
/// </summary>
/// <param name="isDotted"></param>
/// <param name="isTop"></param>
public void InitElementPoint(bool isDotted , bool isTop = false)
{
hitVisiblePen = new Pen(Brushes.Transparent, 1.0); // 初始化碰撞检测线
@@ -148,8 +154,8 @@ namespace Serein.Workbench.Node.View
#region
private readonly StreamGeometry streamGeometry = new StreamGeometry();
private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心
//private Point rightCenterOfStartLocation; // 目标节点选择左侧边缘中心
//private Point leftCenterOfEndLocation; // 起始节点选择右侧边缘中心
private Pen hitVisiblePen; // 初始化碰撞检测线
private Pen visualPen; // 默认可视化Pen
private Point startPoint; // 连接线的起始节点
@@ -158,8 +164,16 @@ namespace Serein.Workbench.Node.View
private double opacity; // 透明度
double linkSize; // 根据缩放比例调整线条粗细
/// <summary>
/// 定义几何形状
/// </summary>
protected override Geometry DefiningGeometry => streamGeometry;
/// <summary>
/// 更新线条颜色
/// </summary>
/// <param name="brush"></param>
public void UpdateLineColor(Brush brush)
{
visualPen = new Pen(brush, 3.0); // 默认可视化Pen

View File

@@ -46,7 +46,7 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 入参控件
/// </summary>
public class ParamsArgControl: Shape
internal class ParamsArgControl: Shape
{
public ParamsArgControl()
{
@@ -172,7 +172,7 @@ namespace Serein.Workbench.Node.View
public abstract class JunctionControlBase : Shape
internal abstract class JunctionControlBase : Shape
{
private readonly FlowNodeService flowNodeService;
protected JunctionControlBase()
@@ -262,16 +262,12 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 禁止连接
/// </summary>
private bool IsConnectionDisable;
/// <summary>
/// 处理鼠标悬停状态
/// </summary>
private bool _isMouseOver;
public bool IsMouseOver
public new bool IsMouseOver
{
get => _isMouseOver;
set

View File

@@ -14,7 +14,7 @@ namespace Serein.Workbench.Node.View
{
#region Model
public class MyLine
internal class MyLine
{
public MyLine(Canvas canvas, ConnectionLineShape line)
{
@@ -32,7 +32,7 @@ namespace Serein.Workbench.Node.View
}
}
public class ConnectingData
internal class ConnectingData
{
/// <summary>
@@ -42,11 +42,11 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 起始控制点
/// </summary>
public JunctionControlBase StartJunction { get; set; }
public JunctionControlBase? StartJunction { get; set; }
/// <summary>
/// 当前的控制点
/// </summary>
public JunctionControlBase CurrentJunction { get; set; }
public JunctionControlBase? CurrentJunction { get; set; }
/// <summary>
/// 开始坐标
/// </summary>
@@ -54,7 +54,7 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 线条样式
/// </summary>
public MyLine MyLine { get; set; }
public MyLine? MyLine { get; set; }
/// <summary>
/// 线条类别(方法调用)
@@ -68,7 +68,7 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 判断当前连接类型
/// </summary>
public JunctionOfConnectionType Type => StartJunction.JunctionType.ToConnectyionType();
public JunctionOfConnectionType Type => StartJunction?.JunctionType.ToConnectyionType() ?? JunctionOfConnectionType.None;
/// <summary>
@@ -113,11 +113,11 @@ namespace Serein.Workbench.Node.View
if (StartJunction.JunctionType == Library.JunctionType.Execute
|| StartJunction.JunctionType == Library.JunctionType.ArgData)
{
MyLine.Line.UpdateStartPoints(point);
MyLine?.Line.UpdateStartPoints(point);
}
else
{
MyLine.Line.UpdateEndPoints(point);
MyLine?.Line.UpdateEndPoints(point);
}
}

View File

@@ -5,7 +5,7 @@ using Serein.Library;
namespace Serein.Workbench.Node.View
{
public class ArgJunctionControl : JunctionControlBase
internal class ArgJunctionControl : JunctionControlBase
{
public ArgJunctionControl()
{

View File

@@ -6,7 +6,7 @@ using Serein.Library;
namespace Serein.Workbench.Node.View
{
public class ExecuteJunctionControl : JunctionControlBase
internal class ExecuteJunctionControl : JunctionControlBase
{
public ExecuteJunctionControl()
{

View File

@@ -6,7 +6,7 @@ using Serein.Library;
namespace Serein.Workbench.Node.View
{
public class NextStepJunctionControl : JunctionControlBase
internal class NextStepJunctionControl : JunctionControlBase
{
//public override JunctionType JunctionType { get; } = JunctionType.NextStep;
public NextStepJunctionControl()

View File

@@ -6,7 +6,7 @@ using Serein.Library;
namespace Serein.Workbench.Node.View
{
public class ResultJunctionControl : JunctionControlBase
internal class ResultJunctionControl : JunctionControlBase
{
public ResultJunctionControl()
{

View File

@@ -13,7 +13,7 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 节点控件基类(控件)
/// </summary>
public abstract class NodeControlBase : UserControl //, IDynamicFlowNode
public abstract class NodeControlBase : UserControl
{
/// <summary>
/// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能)
@@ -34,12 +34,18 @@ namespace Serein.Workbench.Node.View
public NodeControlViewModelBase ViewModel { get; set; }
/// <summary>
/// 节点控件基类,所有节点控件都需要继承这个类
/// </summary>
protected NodeControlBase()
{
this.Background = Brushes.Transparent;
}
/// <summary>
/// 节点控件基类,所有节点控件都需要继承这个类
/// </summary>
/// <param name="viewModelBase"></param>
protected NodeControlBase(NodeControlViewModelBase viewModelBase)
{
ViewModel = viewModelBase;
@@ -85,7 +91,7 @@ namespace Serein.Workbench.Node.View
/// 添加与该节点有关的连接后,记录下来
/// </summary>
/// <param name="connection"></param>
public void AddCnnection(ConnectionControl connection)
internal void AddCnnection(ConnectionControl connection)
{
connectionControls.Add(connection);
}
@@ -94,7 +100,7 @@ namespace Serein.Workbench.Node.View
/// 删除了连接之后,还需要从节点中的记录移除
/// </summary>
/// <param name="connection"></param>
public void RemoveConnection(ConnectionControl connection)
internal void RemoveConnection(ConnectionControl connection)
{
connectionControls.Remove(connection);
connection.Remove(); // 主动删除连接
@@ -163,7 +169,7 @@ namespace Serein.Workbench.Node.View
return null;
}
protected static JunctionControlBase[] GetArgJunction(NodeControlBase nodeControl, MethodDetailsControl methodDetailsControl)
internal static JunctionControlBase[] GetArgJunction(NodeControlBase nodeControl, MethodDetailsControl methodDetailsControl)
{
// 获取 MethodDetailsControl 实例
try

View File

@@ -17,14 +17,16 @@ namespace Serein.Workbench.Node.ViewModel
///// </summary>
public IFlowNode NodeModel { get; }
/// <summary>
/// 节点控制器的基类
/// </summary>
/// <param name="nodeModel"></param>
public NodeControlViewModelBase(IFlowNode nodeModel)
{
NodeModel = nodeModel;
}
/// <summary>
/// 工作台预览基本节点时,避免其中的文本框响应拖拽事件导致卡死
/// </summary>
@@ -32,13 +34,5 @@ namespace Serein.Workbench.Node.ViewModel
private bool isEnabledOnView = true;
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -14,6 +14,10 @@ namespace Serein.Workbench.Node.View
/// </summary>
public partial class ActionNodeControl : NodeControlBase, INodeJunction
{
/// <summary>
/// 构造函数传入ViewModel
/// </summary>
/// <param name="viewModel"></param>
public ActionNodeControl(ActionNodeControlViewModel viewModel) : base(viewModel)
{
DataContext = viewModel;

View File

@@ -10,6 +10,9 @@ namespace Serein.Workbench.Node.View
/// </summary>
public partial class ConditionNodeControl : NodeControlBase, INodeJunction
{
/// <summary>
/// 条件节点控件(用于条件控件)
/// </summary>
public ConditionNodeControl() : base()
{
@@ -22,6 +25,11 @@ namespace Serein.Workbench.Node.View
InitializeComponent();
}
/// <summary>
/// 条件节点控件(用于条件控件)
/// </summary>
/// <param name="viewModel"></param>
public ConditionNodeControl(ConditionNodeControlViewModel viewModel):base(viewModel)
{
DataContext = viewModel;

View File

@@ -18,7 +18,9 @@ namespace Serein.Workbench.Node.View
{
#region
/// <summary>
/// 连接点类型
/// </summary>
public class ConnectionModelBase
{
@@ -48,8 +50,14 @@ namespace Serein.Workbench.Node.View
}
/// <summary>
/// 连接点类型
/// </summary>
public interface IJunctionNode
{
/// <summary>
/// 连接点所属Guid
/// </summary>
string BoundNodeGuid { get; }
}
@@ -73,26 +81,26 @@ namespace Serein.Workbench.Node.View
}
@@ -104,7 +112,7 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 连接控件,表示控件的连接关系
/// </summary>
public class ConnectionControl
internal class ConnectionControl
{
/// <summary>
/// 所在的画布
@@ -155,7 +163,9 @@ namespace Serein.Workbench.Node.View
/// </summary>
/// <param name="Canvas"></param>
/// <param name="invokeType"></param>
public ConnectionControl(Canvas Canvas,
/// <param name="Start"></param>
/// <param name="End"></param>
internal ConnectionControl(Canvas Canvas,
ConnectionInvokeType invokeType,
JunctionControlBase Start,
JunctionControlBase End)
@@ -169,10 +179,15 @@ namespace Serein.Workbench.Node.View
}
/// <summary>
/// 关于入参
/// 关于入参
/// </summary>
/// <param name="LineType"></param>
/// <param name="Canvas"></param>
/// <param name="Type"></param>
/// <param name="argIndex"></param>
/// <param name="argSourceType"></param>
/// <param name="Start"></param>
/// <param name="End"></param>
/// <param name="nodeJunction"></param>
public ConnectionControl(LineType LineType,
Canvas Canvas,
int argIndex,

View File

@@ -10,6 +10,9 @@ namespace Serein.Workbench.Node.View
/// </summary>
public partial class ExpOpNodeControl : NodeControlBase, INodeJunction
{
/// <summary>
/// 表达式操作节点控件
/// </summary>
public ExpOpNodeControl() : base()
{
// 窗体初始化需要
@@ -20,6 +23,11 @@ namespace Serein.Workbench.Node.View
DataContext = ViewModel;
InitializeComponent();
}
/// <summary>
/// 表达式操作节点控件构造函数,使用指定的 ViewModel 初始化
/// </summary>
/// <param name="viewModel"></param>
public ExpOpNodeControl(ExpOpNodeControlViewModel viewModel) :base(viewModel)
{
DataContext = viewModel;

View File

@@ -9,6 +9,10 @@ namespace Serein.Workbench.Node.View
/// </summary>
public partial class FlipflopNodeControl : NodeControlBase, INodeJunction
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="viewModel"></param>
public FlipflopNodeControl(FlipflopNodeControlViewModel viewModel) : base(viewModel)
{
DataContext = viewModel;

View File

@@ -14,6 +14,10 @@ namespace Serein.Workbench.Node.View
public partial class FlowCallNodeControl : NodeControlBase, INodeJunction
{
private new FlowCallNodeControlViewModel ViewModel { get; set; }
/// <summary>
/// 流程接口节点控件构造函数
/// </summary>
public FlowCallNodeControl()
{
var env = App.GetService<IFlowEnvironment>();
@@ -23,6 +27,11 @@ namespace Serein.Workbench.Node.View
base.ViewModel.NodeModel.DisplayName = "[流程接口]";
InitializeComponent();
}
/// <summary>
/// 流程接口节点控件构造函数传入ViewModel
/// </summary>
/// <param name="viewModel"></param>
public FlowCallNodeControl(FlowCallNodeControlViewModel viewModel) : base(viewModel)
{
DataContext = viewModel;

View File

@@ -13,10 +13,14 @@ namespace Serein.Workbench.Node.View
{
private readonly GlobalDataNodeControlViewModel viewModel;
/// <summary>
/// 全局数据控件构造函数,使用默认的全局数据节点模型
/// </summary>
public GlobalDataControl() : base()
{
// 窗体初始化需要
var env = App.GetService<IFlowEnvironment>();
viewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(env));
base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(env));
base.ViewModel.IsEnabledOnView = false;
base.ViewModel.NodeModel.DisplayName = "[全局数据]";
@@ -24,6 +28,11 @@ namespace Serein.Workbench.Node.View
InitializeComponent();
}
/// <summary>
/// 全局数据控件构造函数,使用指定的全局数据节点模型
/// </summary>
/// <param name="viewModel"></param>
public GlobalDataControl(GlobalDataNodeControlViewModel viewModel) : base(viewModel)
{
DataContext = viewModel;
@@ -54,6 +63,11 @@ namespace Serein.Workbench.Node.View
JunctionControlBase[] INodeJunction.ArgDataJunction => throw new NotImplementedException();
/// <summary>
/// 放置节点控件到全局数据面板中
/// </summary>
/// <param name="nodeControl"></param>
/// <returns></returns>
public bool PlaceNode(NodeControlBase nodeControl)
{
if (GlobalDataPanel.Children.Contains(nodeControl))
@@ -65,6 +79,11 @@ namespace Serein.Workbench.Node.View
return true;
}
/// <summary>
/// 从全局数据面板中取出节点控件
/// </summary>
/// <param name="nodeControl"></param>
/// <returns></returns>
public bool TakeOutNode(NodeControlBase nodeControl)
{
if (!GlobalDataPanel.Children.Contains(nodeControl))
@@ -75,6 +94,9 @@ namespace Serein.Workbench.Node.View
return true;
}
/// <summary>
/// 取出所有节点控件(用于删除容器)
/// </summary>
public void TakeOutAll()
{
GlobalDataPanel.Children.Clear();

View File

@@ -58,7 +58,6 @@ namespace Serein.Workbench.Node.View
JunctionControlBase INodeJunction.ReturnDataJunction => throw new Exception();
public JunctionControlBase[] ArgDataJunction => [];
JunctionControlBase[] INodeJunction.ArgDataJunction => [];
}
}

View File

@@ -26,9 +26,11 @@ namespace Serein.Workbench.Node.View
public partial class ScriptNodeControl : NodeControlBase , INodeJunction
{
private ScriptNodeControlViewModel viewModel => (ScriptNodeControlViewModel)ViewModel;
private DispatcherTimer _debounceTimer; // 用于延迟更新
private bool _isUpdating = false; // 防止重复更新
/// <summary>
/// BaseNodesView.xaml 准备节点预览入口
/// </summary>
public ScriptNodeControl()
{
@@ -39,6 +41,11 @@ namespace Serein.Workbench.Node.View
viewModel.NodeModel.DisplayName = "[脚本节点]";
InitializeComponent();
}
/// <summary>
/// 流程运行环境创建节点入口
/// </summary>
/// <param name="viewModel"></param>
public ScriptNodeControl(ScriptNodeControlViewModel viewModel) : base(viewModel)
{
DataContext = viewModel;

View File

@@ -30,25 +30,23 @@ namespace Serein.Workbench.Node.View
InitializeComponent();
}
public UINodeControl(UINodeControlViewModel viewModel) : base(viewModel)
internal UINodeControl(UINodeControlViewModel viewModel) : base(viewModel)
{
ViewModel = viewModel;
DataContext = viewModel;
ViewModel.NodeModel.DisplayName = "[流程UI]";
InitializeComponent();
}
public JunctionControlBase ExecuteJunction => this.ExecuteJunctionControl;
JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl;
public JunctionControlBase NextStepJunction => throw new NotImplementedException();
JunctionControlBase INodeJunction.NextStepJunction => throw new NotImplementedException();
public JunctionControlBase[] ArgDataJunction => throw new NotImplementedException();
JunctionControlBase[] INodeJunction.ArgDataJunction => throw new NotImplementedException();
public JunctionControlBase ReturnDataJunction => throw new NotImplementedException();
JunctionControlBase INodeJunction.ReturnDataJunction => throw new NotImplementedException();
private void NodeControlBase_Loaded(object sender, RoutedEventArgs e)

View File

@@ -4,8 +4,15 @@ using Serein.Workbench.Node.View;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// ActionNodeControlViewModel 类用于表示单动作节点的控制视图模型。
/// </summary>
public class ActionNodeControlViewModel : NodeControlViewModelBase
{
/// <summary>
/// 构造一个新的 ActionNodeControlViewModel 实例。
/// </summary>
/// <param name="node"></param>
public ActionNodeControlViewModel(SingleActionNode node) : base(node)
{
// this.NodelModel = node;

View File

@@ -10,7 +10,7 @@ namespace Serein.Workbench.Node.ViewModel
public class ConditionNodeControlViewModel : NodeControlViewModelBase
{
public new SingleConditionNode NodeModel { get; }
private new SingleConditionNode NodeModel { get; }
/// <summary>
/// 是否为自定义参数

View File

@@ -4,9 +4,15 @@ using Serein.Workbench.Node.View;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// 表达式操作节点控制视图模型
/// </summary>
public class ExpOpNodeControlViewModel: NodeControlViewModelBase
{
public new SingleExpOpNode NodeModel { get; }
/// <summary>
/// 对应的表达式操作节点模型
/// </summary>
public new SingleExpOpNode NodeModel { get; }
//public string Expression
//{
@@ -18,6 +24,10 @@ namespace Serein.Workbench.Node.ViewModel
// }
//}
/// <summary>
/// 表达式操作节点控制视图模型构造函数
/// </summary>
/// <param name="nodeModel"></param>
public ExpOpNodeControlViewModel(SingleExpOpNode nodeModel) : base(nodeModel)
{

View File

@@ -4,10 +4,21 @@ using Serein.Workbench.Node.View;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// 单触发器节点控制视图模型
/// </summary>
public class FlipflopNodeControlViewModel : NodeControlViewModelBase
{
public new SingleFlipflopNode NodelModel { get;}
public FlipflopNodeControlViewModel(SingleFlipflopNode node) : base(node)
/// <summary>
/// 单触发器节点模型
/// </summary>
public SingleFlipflopNode NodelModel { get;}
/// <summary>
/// 构造一个新的单触发器节点控制视图模型实例。
/// </summary>
/// <param name="node"></param>
public FlipflopNodeControlViewModel(SingleFlipflopNode node) : base(node)
{
this.NodelModel = node;
}

View File

@@ -50,6 +50,10 @@ namespace Serein.Workbench.Node.ViewModel
private readonly FlowNodeService flowNodeService;
private readonly IFlowEEForwardingService flowEEForwardingService;
/// <summary>
/// 流程接口节点构造函数
/// </summary>
/// <param name="node"></param>
public FlowCallNodeControlViewModel(SingleFlowCallNode node) : base(node)
{
this.FlowCallNode = node;

View File

@@ -5,9 +5,12 @@ using System.Windows.Input;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// 全局数据节点控制视图模型
/// </summary>
public class GlobalDataNodeControlViewModel : NodeControlViewModelBase
{
private SingleGlobalDataNode NodeModel => (SingleGlobalDataNode)base.NodeModel;
private new SingleGlobalDataNode NodeModel => (SingleGlobalDataNode)base.NodeModel;
/// <summary>
/// 复制全局数据表达式
@@ -19,7 +22,10 @@ namespace Serein.Workbench.Node.ViewModel
/// </summary>
public ICommand CommandRefreshData { get; }
/// <summary>
/// 全局数据节点控制视图模型构造函数
/// </summary>
/// <param name="node"></param>
public GlobalDataNodeControlViewModel(SingleGlobalDataNode node) : base(node)
{
CommandCopyDataExp = new RelayCommand( o =>

View File

@@ -6,9 +6,12 @@ using System.Windows.Input;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// 动态脚本节点控制视图模型
/// </summary>
public class NetScriptNodeControlViewModel : NodeControlViewModelBase
{
private SingleNetScriptNode NodeModel => (SingleNetScriptNode)base.NodeModel;
private new SingleNetScriptNode NodeModel => (SingleNetScriptNode)base.NodeModel;
public string Tips
{
@@ -45,22 +48,12 @@ public class FlowLibrary
}
}";
CommandOpenScriptEdit = new RelayCommand(async o =>
CommandOpenScriptEdit = new RelayCommand(o =>
{
DynamicCompilerView dynamicCompilerView = new DynamicCompilerView();
dynamicCompilerView.ScriptCode = this.Script ;
dynamicCompilerView.OnCompileComplete = OnCompileComplete;
dynamicCompilerView.ShowDialog();
//try
//{
// var result = await NodeModel.ExecutingAsync(new Library.DynamicContext(nodeModel.Env));
// nodeModel.Env.WriteLine(InfoType.INFO, result?.ToString());
//}
//catch (Exception ex)
//{
// nodeModel.Env.WriteLine(InfoType.ERROR, ex.ToString());
//}
});
NodeModel1 = nodeModel;
}
@@ -86,6 +79,10 @@ public class FlowLibrary
/// 打开编辑窗口
/// </summary>
public ICommand CommandOpenScriptEdit { get; }
/// <summary>
/// 节点模型
/// </summary>
public NodeModelBase NodeModel1 { get; }
}
}

View File

@@ -13,9 +13,13 @@ using System.Windows.Input;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// 脚本节点控制视图模型
/// </summary>
public class ScriptNodeControlViewModel : NodeControlViewModelBase
{
private SingleScriptNode NodeModel => (SingleScriptNode)base.NodeModel;
private new SingleScriptNode NodeModel => (SingleScriptNode)base.NodeModel;
public string? Script
{

View File

@@ -12,9 +12,13 @@ using System.Windows.Controls;
namespace Serein.Workbench.Node.ViewModel
{
/// <summary>
/// UI节点控制器视图模型
/// </summary>
public partial class UINodeControlViewModel : NodeControlViewModelBase
{
private SingleUINode NodeModel => (SingleUINode)base.NodeModel;
private new SingleUINode NodeModel => (SingleUINode)base.NodeModel;
//public IEmbeddedContent Adapter => NodeModel.Adapter;
/// <summary>

View File

@@ -11,7 +11,11 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net462|AnyCPU'">
<NoWarn>1701;1702;1573;CS0414</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Node\NodeModel\**" />
<Compile Remove="Themes\Condition\**" />

View File

@@ -18,7 +18,7 @@ namespace Serein.Workbench.Services
/// <summary>
/// 流程节点管理
/// </summary>
public class FlowNodeService
internal class FlowNodeService
{
@@ -120,7 +120,7 @@ namespace Serein.Workbench.Services
/// <summary>
/// 连接数据
/// </summary>
public ConnectingData ConnectingData { get; } = new ConnectingData();
internal ConnectingData ConnectingData { get; } = new ConnectingData();
#endregion
@@ -471,12 +471,12 @@ namespace Serein.Workbench.Services
return NodeControls.TryGetValue(nodeGuid, out nodeControl);
}
/// <summary>
/// 从Guid获取画布视图
/// </summary>
/// <param name="nodeGuid"></param>
/// <param name="nodeControl"></param>
/// <param name="flowCanvas"></param>
/// <returns></returns>
private bool TryGetCanvas(string nodeGuid, out FlowCanvasView flowCanvas)
{
@@ -643,8 +643,7 @@ namespace Serein.Workbench.Services
}
catch (Exception ex)
{
//SereinEnv.WriteLine(InfoType.ERROR, $"粘贴节点时发生异常:{ex}");
SereinEnv.WriteLine(InfoType.ERROR, $"粘贴节点时发生异常:{ex}");
}
// SereinEnv.WriteLine(InfoType.INFO, $"剪贴板文本内容: {clipboardText}");
}

View File

@@ -11,35 +11,46 @@ using System.Threading.Tasks;
namespace Serein.Workbench.Services
{
/// <summary>
/// 流程项目服务
/// </summary>
public class FlowProjectService
{
private readonly IFlowEnvironment flowEnvironment;
/// <summary>
/// 流程项目服务
/// </summary>
/// <param name="flowEnvironment"></param>
public FlowProjectService(IFlowEnvironment flowEnvironment)
{
this.flowEnvironment = flowEnvironment;
}
/// <summary>
/// 启动流程项目管理服务器
/// </summary>
public void StartProjectManagementServer()
{
// CollabrationSideManagement
}
/// <summary>
/// 加载本地流程项目到当前环境中
/// </summary>
/// <param name="filePath"></param>
public void LoadLocalProject(string filePath)
{
if (File.Exists(filePath))
{
/*
var dir = Path.GetDirectoryName(filePath);
var flowEnvInfo = new FlowEnvInfo
{
Project = FlowProjectData,
};*/
flowEnvironment.LoadProject(filePath);
}
}
/// <summary>
/// 选择本地流程项目文件并加载到当前环境中
/// </summary>
public void SelectProjectFile()
{
System.Windows.Forms.OpenFileDialog openFileDialog = new System.Windows.Forms.OpenFileDialog();

View File

@@ -10,7 +10,16 @@ using static System.Windows.Forms.AxHost;
namespace Serein.Workbench.Services
{
/// <summary>
/// 全局按键事件委托
/// </summary>
/// <param name="key"></param>
public delegate void KeyDownEventHandler(Key key);
/// <summary>
/// 全局按键抬起事件委托
/// </summary>
/// <param name="key"></param>
public delegate void KeyUpEventHandler(Key key);
/// <summary>
@@ -18,7 +27,14 @@ namespace Serein.Workbench.Services
/// </summary>
public interface IKeyEventService
{
/// <summary>
/// 按键按下事件
/// </summary>
event KeyDownEventHandler OnKeyDown;
/// <summary>
/// 按键抬起事件
/// </summary>
event KeyUpEventHandler OnKeyUp;
/// <summary>
@@ -56,6 +72,9 @@ namespace Serein.Workbench.Services
/// </summary>
public event KeyUpEventHandler OnKeyUp;
/// <summary>
/// 全局按键事件服务构造函数
/// </summary>
public KeyEventService()
{
var arr = Enum.GetValues<Key>();
@@ -66,6 +85,12 @@ namespace Serein.Workbench.Services
}
private readonly bool[] KeysState;
/// <summary>
/// 获取某个按键的状态
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool GetKeyState(Key key)
{
return KeysState[(int)key];
@@ -73,7 +98,10 @@ namespace Serein.Workbench.Services
/// <summary>
/// 按键按下事件
/// </summary>
/// <param name="key"></param>
public void KeyDown(Key key)
{
KeysState[(int)key] = true;
@@ -81,6 +109,10 @@ namespace Serein.Workbench.Services
//Debug.WriteLine($"按键按下事件:{key}");
}
/// <summary>
/// 按键抬起事件
/// </summary>
/// <param name="key"></param>
public void KeyUp(Key key)
{
KeysState[(int)key] = false;

View File

@@ -9,8 +9,14 @@ using System.Windows;
namespace Serein.Workbench.Themes
{
/// <summary>
/// BindableRichTextBox 是一个可绑定的 RichTextBox 控件,允许将 FlowDocument 对象绑定到其 Document 属性。
/// </summary>
public partial class BindableRichTextBox : RichTextBox
{
/// <summary>
/// BindableRichTextBox 的依赖属性,允许绑定 FlowDocument 对象到 RichTextBox 的 Document 属性。
/// </summary>
public new FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }

View File

@@ -26,6 +26,9 @@ namespace Serein.Workbench.Themes
{
public Action<string,object> SelectObj { get; set; }
/// <summary>
/// IOC对象视图控件
/// </summary>
public IOCObjectViewControl()
{
InitializeComponent();
@@ -89,6 +92,9 @@ namespace Serein.Workbench.Themes
}
}
/// <summary>
/// 清空所有实例显示
/// </summary>
public void ClearObjItem()
{
DependenciesListBox.Dispatcher.Invoke(() =>
@@ -108,6 +114,10 @@ namespace Serein.Workbench.Themes
}
}
/// <summary>
/// 移除一个实例的显示
/// </summary>
/// <param name="key"></param>
public void RemoveDependenciesInstance(string key)
{
object? itemControl = null;

View File

@@ -19,8 +19,14 @@ namespace Serein.Workbench.Themes
/// </summary>
public partial class InputDialog : Window
{
/// <summary>
/// 输入对话框的输入值
/// </summary>
public string InputValue { get; private set; }
/// <summary>
/// 初始化输入对话框的新实例
/// </summary>
public InputDialog()
{
InitializeComponent();

View File

@@ -11,9 +11,19 @@ using System.Windows.Input;
namespace Serein.Workbench.Themes
{
/// <summary>
/// 描述或名称转换器
/// </summary>
public class DescriptionOrNameConverter : IMultiValueConverter
{
/// <summary>
/// 将源类型的数组转换为目标类型的值。
/// </summary>
/// <param name="values"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string description = values[0] as string;
@@ -21,15 +31,34 @@ namespace Serein.Workbench.Themes
return string.IsNullOrWhiteSpace(description) ? name : description;
}
/// <summary>
/// 将值从目标类型转换回源类型的数组。
/// </summary>
/// <param name="value"></param>
/// <param name="targetTypes"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 多条件转换器,根据参数类型和是否启用来决定返回的模板
/// </summary>
public class MultiConditionConverter : IMultiValueConverter
{
/// <summary>
/// 将源类型的数组转换为目标类型的值。
/// </summary>
/// <param name="values"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is Type valueType && values[1] is bool isEnabled)
@@ -51,30 +80,53 @@ namespace Serein.Workbench.Themes
return DependencyProperty.UnsetValue;
}
/// <summary>
/// 将值从目标类型转换回源类型的数组。
/// </summary>
/// <param name="value"></param>
/// <param name="targetTypes"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 数据上下文代理类用于绑定到DataContextProperty
/// </summary>
public class DataContextProxy : Freezable
{
/// <summary>
/// 数据上下文代理类构造函数
/// </summary>
public DataContextProxy()
{
BindingOperations.SetBinding(this, DataContextProperty, new Binding());
}
/// <summary>
/// 数据上下文属性
/// </summary>
public ParameterDetails DataContext
{
get { return (ParameterDetails)GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
/// <summary>
/// 数据上下文依赖属性
/// </summary>
public static readonly DependencyProperty DataContextProperty = FrameworkElement
.DataContextProperty.AddOwner(typeof(DataContextProxy));
/// <summary>
/// 创建一个新的实例重写Freezable的CreateInstanceCore方法。
/// </summary>
/// <returns></returns>
protected override Freezable CreateInstanceCore()
{
return new DataContextProxy();
@@ -123,10 +175,15 @@ namespace Serein.Workbench.Themes
//var MethodDetails = (MethodDetails)args.NewValue;
//MethodDetails.ExplicitDatas[0].
}
/// <summary>
/// 添加参数命令
/// </summary>
public ICommand CommandAddParams { get; }
/// <summary>
/// 方法参数控件构造函数
/// </summary>
public MethodDetailsControl()
{
CommandAddParams = new RelayCommand(ExecuteAddParams);

View File

@@ -9,6 +9,9 @@ using static Serein.Workbench.Themes.TypeViewerWindow;
namespace Serein.Workbench.Themes
{
/// <summary>
/// FlowDataDetails 类用于存储对象的详细信息,包括名称、类型、数据类型、数据值和数据路径等。
/// </summary>
public class FlowDataDetails
{
/// <summary>
@@ -83,11 +86,12 @@ namespace Serein.Workbench.Themes
// 用于存储当前展开的节点路径
private HashSet<string> expandedNodePaths = new HashSet<string>();
/// <summary>
/// 加载对象信息,展示其成员
/// </summary>
/// <param name="key">与对象关联的Key,用于管理对象</param>
/// <param name="obj">要展示的对象</param>
public void LoadObjectInformation(string key, object obj)
{
@@ -113,7 +117,7 @@ namespace Serein.Workbench.Themes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void UpMonitorExpressionButton_Click(object sender, RoutedEventArgs e)
private void UpMonitorExpressionButton_Click(object sender, RoutedEventArgs e)
{
//if (FlowEnvironment is not null && await FlowEnvironment.AddInterruptExpressionAsync(monitorKey, MonitorExpression)) // 对象预览器尝试添加中断表达式
//{
@@ -441,6 +445,7 @@ namespace Serein.Workbench.Themes
/// </summary>
/// <param name="obj"></param>
/// <param name="property"></param>
/// <param name="value"></param>
/// <returns></returns>
private string GetPropertyValue(object obj, PropertyInfo property,out object? value)
{
@@ -469,6 +474,7 @@ namespace Serein.Workbench.Themes
/// </summary>
/// <param name="obj"></param>
/// <param name="field"></param>
/// <param name="value"></param>
/// <returns></returns>
private string GetFieldValue(object obj, FieldInfo field, out object? value)
{
@@ -486,6 +492,7 @@ namespace Serein.Workbench.Themes
}
}
#if false
/// <summary>
@@ -651,3 +658,5 @@ namespace Serein.Workbench.Themes
//}
#endif

View File

@@ -157,7 +157,9 @@ namespace Serein.Workbench.Themes
/// <summary>
/// 设置子项节点的事件
/// </summary>
/// <param name="memberNode"></param>
/// <param name="member"></param>
/// <param name="contextMenu"></param>
/// <returns></returns>
private bool ConfigureTreeItemMenu(TreeViewItem memberNode, MemberInfo member,out ContextMenu? contextMenu)
{

View File

@@ -11,15 +11,20 @@ namespace Serein.Workbench.Tool
/// </summary>
public class GuidReplacer
{
private class TrieNode
{
public Dictionary<char, TrieNode> Children = new();
public string Replacement; // 替换后的值
public string Replacement = string.Empty; // 替换后的值
}
private readonly TrieNode _root = new();
// 构建字典树
/// <summary>
/// 构建字典树
/// </summary>
/// <param name="guid"></param>
/// <param name="replacement"></param>
public void AddReplacement(string guid, string replacement)
{
var current = _root;
@@ -34,7 +39,11 @@ namespace Serein.Workbench.Tool
current.Replacement = replacement;
}
// 替换逻辑
/// <summary>
/// 替换逻辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public string Replace(string input)
{
var result = new StringBuilder();

View File

@@ -20,7 +20,7 @@ namespace Serein.Workbench.ViewModels
/// <summary>
/// 流程编辑数据视图
/// </summary>
public partial class FlowEditViewModel : ObservableObject
internal partial class FlowEditViewModel : ObservableObject
{
/// <summary>
/// 画布集合

View File

@@ -8,7 +8,7 @@ using System.Windows.Input;
namespace Serein.Workbench.ViewModels
{
public class MainMenuBarViewModel : ObservableObject
internal class MainMenuBarViewModel : ObservableObject
{
private readonly IFlowEnvironment flowEnvironment;
private readonly FlowNodeService flowNodeService;

View File

@@ -10,10 +10,17 @@ using System.Windows;
namespace Serein.Workbench.ViewModels
{
/// <summary>
/// 主视图模型
/// </summary>
public class MainViewModel : ObservableObject
{
private readonly IKeyEventService keyEventService;
/// <summary>
/// 主视图模型构造函数
/// </summary>
/// <param name="keyEventService"></param>
public MainViewModel(IKeyEventService keyEventService)
{

View File

@@ -23,6 +23,9 @@ namespace Serein.Workbench.Views
/// </summary>
public partial class BaseNodesView : UserControl
{
/// <summary>
/// 基础节点视图构造函数
/// </summary>
public BaseNodesView()
{
this.DataContext = App.GetService<Locator>().BaseNodesViewModel;

View File

@@ -74,10 +74,6 @@ namespace Serein.Workbench.Views
/// </summary>
private bool IsSelectControl;
/// <summary>
/// 标记是否正在进行连接操作
/// </summary>
//private bool IsConnecting;
/// <summary>
/// 标记是否正在拖动控件
/// </summary>
private bool IsControlDragging;
@@ -124,6 +120,10 @@ namespace Serein.Workbench.Views
#region
/// <summary>
/// FlowCanvasView 构造函数
/// </summary>
/// <param name="model"></param>
public FlowCanvasView(FlowCanvasDetails model)
{
var vm = App.GetService<Locator>().FlowCanvasViewModel;
@@ -615,7 +615,7 @@ namespace Serein.Workbench.Views
if (key == Key.V && (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl)))
{
string clipboardText = Clipboard.GetText(TextDataFormat.Text); // 获取复制的文本
string nodesText = "";
string? nodesText = "";
try
{
var jobject = JObject.Parse(clipboardText);
@@ -623,6 +623,7 @@ namespace Serein.Workbench.Views
}
catch (Exception ex)
{
SereinEnv.WriteLine(InfoType.ERROR, $"粘贴节点信息失败: {ex.Message}");
return;
}
@@ -878,7 +879,7 @@ namespace Serein.Workbench.Views
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void FlowChartCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
private void FlowChartCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (IsSelectControl)
{
@@ -895,7 +896,7 @@ namespace Serein.Workbench.Views
// 创建连线
var cd = flowNodeService.ConnectingData;
if (cd.IsCreateing)
if (cd.IsCreateing && cd.CurrentJunction is not null)
{
if (cd.IsCanConnected)
{
@@ -1593,6 +1594,12 @@ namespace Serein.Workbench.Views
#region Plan A
/// <summary>
/// 对齐选中的控件,支持多种对齐方式。
/// </summary>
/// <param name="selectNodeControls"></param>
/// <param name="proximityThreshold"></param>
/// <param name="spacing"></param>
public void AlignControlsWithGrouping(List<NodeControlBase> selectNodeControls, double proximityThreshold = 50, double spacing = 10)
{
if (selectNodeControls is null || selectNodeControls.Count < 2)
@@ -1673,6 +1680,11 @@ namespace Serein.Workbench.Views
#endregion
#region Plan B
/// <summary>
/// 使用动态规划对齐选中的控件,确保控件之间有间距,并且不重叠。
/// </summary>
/// <param name="selectNodeControls"></param>
/// <param name="spacing"></param>
public void AlignControlsWithDynamicProgramming(List<NodeControlBase> selectNodeControls, double spacing = 10)
{
if (selectNodeControls is null || selectNodeControls.Count < 2)
@@ -1751,6 +1763,10 @@ namespace Serein.Workbench.Views
#endregion
/// <summary>
/// 对齐模式枚举
/// </summary>
public enum AlignMode
{
/// <summary>
@@ -1780,7 +1796,13 @@ namespace Serein.Workbench.Views
Grouping,
}
/// <summary>
/// 对齐控件,支持多种对齐方式。
/// </summary>
/// <param name="selectNodeControls"></param>
/// <param name="alignMode"></param>
/// <param name="proximityThreshold"></param>
/// <param name="spacing"></param>
public void AlignControlsWithGrouping(List<NodeControlBase> selectNodeControls, AlignMode alignMode, double proximityThreshold = 50, double spacing = 10)
{
if (selectNodeControls is null || selectNodeControls.Count < 2)

View File

@@ -31,7 +31,9 @@ namespace Serein.Workbench.Views
/// </summary>
public partial class FlowEditView : UserControl
{
/// <summary>
/// 流程编辑视图构造函数
/// </summary>
public FlowEditView()
{
this.DataContext = App.GetService<Locator>().FlowEditViewModel;

View File

@@ -23,6 +23,10 @@ namespace Serein.Workbench.Views
public partial class FlowLibrarysView : UserControl
{
private FlowLibrarysViewModel ViewModel => DataContext as FlowLibrarysViewModel ?? throw new ArgumentNullException();
/// <summary>
/// FlowLibrarysView 构造函数
/// </summary>
public FlowLibrarysView()
{
this.DataContext = App.GetService<Locator>().FlowLibrarysViewModel;

View File

@@ -21,6 +21,10 @@ namespace Serein.Workbench.Views
public partial class FlowWorkbenchView : Window
{
private FlowWorkbenchViewModel ViewModel => ViewModel as FlowWorkbenchViewModel;
/// <summary>
/// FlowWorkbenchView 的交互逻辑
/// </summary>
public FlowWorkbenchView()
{
this.DataContext = App.GetService<Locator>().FlowWorkbenchViewModel;
@@ -49,6 +53,10 @@ namespace Serein.Workbench.Views
System.Windows.Application.Current.Shutdown();
}
/// <summary>
/// 处理鼠标按下事件,确保点击空白区域时清除焦点
/// </summary>
/// <param name="e"></param>
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
// 获取当前的焦点控件

View File

@@ -21,6 +21,9 @@ namespace Serein.Workbench.Views
/// </summary>
public partial class MainMenuBarView : UserControl
{
/// <summary>
/// MainMenuBarView 的构造函数
/// </summary>
public MainMenuBarView()
{
this.DataContext = App.GetService<Locator>().MainMenuBarViewModel;

View File

@@ -21,6 +21,9 @@ namespace Serein.Workbench.Views
/// </summary>
public partial class MainView : UserControl
{
/// <summary>
/// MainView 的构造函数
/// </summary>
public MainView()
{
this.DataContext = App.GetService<Locator>().MainViewModel;

View File

@@ -26,6 +26,10 @@ namespace Serein.Workbench.Views
{
private readonly ViewCanvasInfoViewModel ViewModel;
private readonly ViewNodeInfoViewModel NodeInfoViewModel;
/// <summary>
/// 画布信息查看视图
/// </summary>
public ViewCanvasInfoView()
{
this.ViewModel = App.GetService<ViewCanvasInfoViewModel>();

View File

@@ -22,6 +22,10 @@ namespace Serein.Workbench.Views
public partial class ViewNodeInfoView : UserControl
{
private readonly ViewNodeInfoViewModel ViewModel;
/// <summary>
/// ViewNodeInfoView 的交互逻辑
/// </summary>
public ViewNodeInfoView()
{

View File

@@ -23,6 +23,9 @@ namespace Serein.Workbench.Views
{
private readonly ViewNodeMethodInfoViewModel ViewModel;
/// <summary>
/// ViewNodeMethodInfoView 的交互逻辑
/// </summary>
public ViewNodeMethodInfoView()
{
ViewModel = App.GetService<Locator>().ViewNodeMethodInfoViewModel;