mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
实现了多画布下,节点的复制粘贴功能
This commit is contained in:
@@ -1097,16 +1097,19 @@ namespace Serein.Library.Api
|
||||
void SetUIContextOperation(UIContextOperation uiContextOperation);
|
||||
|
||||
/// <summary>
|
||||
/// 开始运行
|
||||
/// 开始运行流程
|
||||
/// </summary>
|
||||
Task<bool> StartFlowAsync();
|
||||
/// <param name="canvasGuids">需要运行的流程Guid</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> StartFlowAsync(string[] canvasGuids);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从选定的节点开始运行
|
||||
/// </summary>
|
||||
/// <param name="startNodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> StartAsyncInSelectNode(string startNodeGuid);
|
||||
Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid);
|
||||
|
||||
/// <summary>
|
||||
/// 结束运行
|
||||
|
||||
@@ -7,12 +7,5 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// 拖拽创建节点使用的数据
|
||||
/// </summary>
|
||||
public class MoveNodeData
|
||||
{
|
||||
public NodeControlType NodeControlType { get; set; }
|
||||
public MethodDetailsInfo MethodDetailsInfo { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -101,10 +101,10 @@ namespace Serein.Library
|
||||
// 生成参数列表
|
||||
ParameterData[] parameterData = nodeModel.SaveParameterInfo();
|
||||
|
||||
NodeInfo nodeInfo = new NodeInfo
|
||||
var nodeInfo = new NodeInfo
|
||||
{
|
||||
Guid = nodeModel.Guid,
|
||||
CanvasGuid = nodeModel.CanvasGuid,
|
||||
Guid = nodeModel.Guid,
|
||||
AssemblyName = nodeModel.MethodDetails.AssemblyName,
|
||||
MethodName = nodeModel.MethodDetails?.MethodName,
|
||||
Label = nodeModel.MethodDetails?.MethodAnotherName,
|
||||
@@ -130,10 +130,12 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 从节点信息加载节点
|
||||
/// </summary>
|
||||
/// <param name="nodeModel"></param>
|
||||
/// <param name="nodeInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static void LoadInfo(this NodeModelBase nodeModel, NodeInfo nodeInfo)
|
||||
{
|
||||
nodeModel.CanvasGuid = nodeInfo.CanvasGuid;
|
||||
nodeModel.Guid = nodeInfo.Guid;
|
||||
nodeModel.Position = nodeInfo.Position ?? new PositionOfUI(0, 0);// 加载位置信息
|
||||
var md = nodeModel.MethodDetails; // 当前节点的方法说明
|
||||
@@ -191,6 +193,7 @@ namespace Serein.Library
|
||||
/// <summary>
|
||||
/// 开始执行
|
||||
/// </summary>
|
||||
/// <param name="nodeModel"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="token">流程运行</param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Serein.Library
|
||||
Env = env;
|
||||
}
|
||||
|
||||
|
||||
public IFlowEnvironment Env { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -79,8 +80,6 @@ namespace Serein.Library
|
||||
/// </summary>
|
||||
private string _startNode;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Serein.Library
|
||||
public string NodeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法说明
|
||||
/// 方法别名
|
||||
/// </summary>
|
||||
public string MethodAnotherName { get; set; }
|
||||
|
||||
|
||||
@@ -336,6 +336,7 @@ namespace Serein.Library
|
||||
_x = x; _y = y;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 指示控件在画布的横向向方向上的位置
|
||||
/// </summary>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<SatelliteResourceLanguages>no</SatelliteResourceLanguages>
|
||||
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
|
||||
@@ -368,27 +368,87 @@ namespace Serein.NodeFlow.Env
|
||||
/// 异步运行
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> StartFlowAsync()
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
#region 校验参数
|
||||
HashSet<string> guids = new HashSet<string>();
|
||||
bool isBreak = false;
|
||||
foreach (var canvasGuid in canvasGuids)
|
||||
{
|
||||
if (guids.Contains(canvasGuid))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布重复,停止运行。{canvasGuid}");
|
||||
isBreak = true;
|
||||
}
|
||||
if (!FlowCanvass.ContainsKey(canvasGuid))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{canvasGuid}");
|
||||
isBreak = true;
|
||||
}
|
||||
var count = NodeModels.Values.Count(n => n.CanvasGuid.Equals(canvasGuid));
|
||||
if(count == 0)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布没有节点,停止运行。{canvasGuid}");
|
||||
isBreak = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
guids.Add(canvasGuid);
|
||||
}
|
||||
}
|
||||
if (isBreak)
|
||||
{
|
||||
guids.Clear();
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 初始化每个画布的数据,转换为流程任务
|
||||
Dictionary<string, FlowTask> flowTasks = [];
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
if (!TryGetCanvasModel(guid, out var canvasModel))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在,停止运行。{guid}");
|
||||
return false;
|
||||
}
|
||||
var ft = new FlowTask();
|
||||
ft.GetNodes = () => NodeModels.Values.Where(node => node.CanvasGuid.Equals(guid)).ToList();
|
||||
var startNodeModel = NodeModels.GetValueOrDefault(canvasModel.StartNode);
|
||||
if(startNodeModel is null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, $"画布不存在起始节点,将停止运行。{guid}");
|
||||
return false;
|
||||
}
|
||||
ft.GetStartNode = () => startNodeModel;
|
||||
flowTasks.Add(guid, ft);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
IOC.Reset();
|
||||
IOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
|
||||
|
||||
var flowTaskOptions = new FlowWorkOptions
|
||||
{
|
||||
Environment = this,
|
||||
FlowContextPool = new ObjectPool<IDynamicContext>(() => new DynamicContext(this)),
|
||||
//Nodes = NodeModels.Values.ToList(),
|
||||
AutoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType(),
|
||||
InitMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init),
|
||||
Environment = this, // 流程
|
||||
Flows = flowTasks,
|
||||
FlowContextPool = new ObjectPool<IDynamicContext>(() => new DynamicContext(this)), // 上下文对象池
|
||||
AutoRegisterTypes = this.FlowLibraryManagement.GetaAutoRegisterType(), // 需要自动实例化的类型
|
||||
InitMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Init),
|
||||
LoadMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Loading),
|
||||
ExitMds = this.FlowLibraryManagement.GetMdsOnFlowStart(NodeType.Exit),
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
flowTaskManagement = new FlowWorkManagement(flowTaskOptions);
|
||||
var cts = new CancellationTokenSource();
|
||||
try
|
||||
{
|
||||
var t =await flowTaskManagement.RunAsync(cts.Token);
|
||||
var t = await flowTaskManagement.RunAsync(cts.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -405,12 +465,13 @@ namespace Serein.NodeFlow.Env
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从选定节点开始运行
|
||||
/// </summary>
|
||||
/// <param name="startNodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> StartAsyncInSelectNode(string startNodeGuid)
|
||||
public async Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
|
||||
{
|
||||
|
||||
if (flowTaskManagement is null)
|
||||
@@ -425,12 +486,6 @@ namespace Serein.NodeFlow.Env
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//var getExp = "@get .DebugSetting.IsEnable";
|
||||
//var getExpResult1 = SerinExpressionEvaluator.Evaluate(getExp, nodeModel,out _);
|
||||
//var setExp = "@set .DebugSetting.IsEnable = false";
|
||||
//SerinExpressionEvaluator.Evaluate(setExp, nodeModel,out _);
|
||||
//var getExpResult2 = SerinExpressionEvaluator.Evaluate(getExp, nodeModel, out _);
|
||||
|
||||
await flowTaskManagement.StartFlowInSelectNodeAsync(this, nodeModel);
|
||||
return true;
|
||||
}
|
||||
@@ -559,9 +614,22 @@ namespace Serein.NodeFlow.Env
|
||||
LoadLibrary(dllFilePath); // 加载项目文件时加载对应的程序集
|
||||
}
|
||||
|
||||
|
||||
|
||||
_ = Task.Run( async () =>
|
||||
{
|
||||
{
|
||||
// 加载画布
|
||||
foreach (var canvasInfo in projectData.Canvass)
|
||||
{
|
||||
LoadCanvas(canvasInfo);
|
||||
}
|
||||
await LoadNodeInfosAsync(projectData.Nodes.ToList()); // 加载节点信息
|
||||
|
||||
// 加载画布
|
||||
foreach (var canvasInfo in projectData.Canvass)
|
||||
{
|
||||
await SetStartNodeAsync(canvasInfo.Guid, canvasInfo.StartNode); // 设置起始节点
|
||||
}
|
||||
//await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
|
||||
});
|
||||
|
||||
@@ -779,20 +847,31 @@ namespace Serein.NodeFlow.Env
|
||||
/// <returns></returns>
|
||||
public async Task<FlowCanvasDetailsInfo> CreateCanvasAsync(string canvasName, int width, int height)
|
||||
{
|
||||
var model = new FlowCanvasDetails(this)
|
||||
var info = new FlowCanvasDetailsInfo()
|
||||
{
|
||||
Guid = Guid.NewGuid().ToString(),
|
||||
Height = height,
|
||||
Width = width,
|
||||
ViewX = 0,
|
||||
ViewY = 0,
|
||||
ScaleY = 1,
|
||||
ScaleX = 1,
|
||||
Name = !string.IsNullOrWhiteSpace(canvasName) ? canvasName : $"流程图{_addCanvasCount++}",
|
||||
};
|
||||
var model = LoadCanvas(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private FlowCanvasDetails LoadCanvas(FlowCanvasDetailsInfo info)
|
||||
{
|
||||
var model = new FlowCanvasDetails(this);
|
||||
model.LoadInfo(info);
|
||||
FlowCanvass.Add(model.Guid, model);
|
||||
await UIContextOperation.InvokeAsync(() =>
|
||||
UIContextOperation.InvokeAsync(() =>
|
||||
{
|
||||
OnCanvasCreate.Invoke(new CanvasCreateEventArgs(model));
|
||||
});
|
||||
var info = model.ToInfo();
|
||||
return info;
|
||||
return model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -957,7 +1036,7 @@ namespace Serein.NodeFlow.Env
|
||||
#region 确定节点之间的参数调用关系
|
||||
foreach (var toNode in NodeModels.Values)
|
||||
{
|
||||
var canvasGuid = toNode.Guid;
|
||||
var canvasGuid = toNode.CanvasGuid;
|
||||
if (toNode.MethodDetails.ParameterDetailss == null)
|
||||
{
|
||||
continue;
|
||||
@@ -1727,7 +1806,7 @@ namespace Serein.NodeFlow.Env
|
||||
private bool TryAddNode(NodeModelBase nodeModel)
|
||||
{
|
||||
nodeModel.Guid ??= Guid.NewGuid().ToString();
|
||||
NodeModels[nodeModel.Guid] = nodeModel;
|
||||
NodeModels.TryAdd(nodeModel.Guid, nodeModel);
|
||||
|
||||
// 如果是触发器,则需要添加到专属集合中
|
||||
if (nodeModel is SingleFlipflopNode flipflopNode)
|
||||
@@ -1944,32 +2023,22 @@ namespace Serein.NodeFlow.Env
|
||||
/// <summary>
|
||||
/// 更改起点节点
|
||||
/// </summary>
|
||||
/// <param name="newStartNode"></param>
|
||||
/// <param name="oldStartNode"></param>
|
||||
/// <param name="cavnasModel">节点所在的画布</param>
|
||||
/// <param name="newStartNode">起始节点</param>
|
||||
private void SetStartNode(FlowCanvasDetails cavnasModel, NodeModelBase newStartNode)
|
||||
{
|
||||
var oldNodeGuid = cavnasModel.StartNode;
|
||||
/*if(TryGetNodeModel(oldNodeGuid, out var newStartNodeModel))
|
||||
{
|
||||
newStartNode.IsStart = false;
|
||||
}*/
|
||||
cavnasModel.StartNode = newStartNode.Guid;
|
||||
//newStartNode.IsStart = true;
|
||||
|
||||
UIContextOperation?.Invoke(() => OnStartNodeChange?.Invoke(new StartNodeChangeEventArgs(cavnasModel.Guid, oldNodeGuid, cavnasModel.StartNode)));
|
||||
|
||||
//if (OperatingSystem.IsWindows())
|
||||
//{
|
||||
// }
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 输出内容
|
||||
///// </summary>
|
||||
///// <param name="msg"></param>
|
||||
//private void Output(string msg)
|
||||
//{
|
||||
// if (OperatingSystem.IsWindows())
|
||||
// {
|
||||
// UIContextOperation?.Invoke(() => OnEnvOut?.Invoke(msg));
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 向容器登记缓存的持久化实例
|
||||
/// </summary>
|
||||
|
||||
@@ -263,7 +263,7 @@ namespace Serein.NodeFlow.Env
|
||||
/// <param name="toNodeJunctionType">目标节点控制点</param>
|
||||
/// <param name="invokeType">决定了方法执行后的后继行为</param>
|
||||
public async Task<bool> ConnectInvokeNodeAsync(string canvasGuid,
|
||||
string fromNodeGuid,
|
||||
string fromNodeGuid,
|
||||
string toNodeGuid,
|
||||
JunctionType fromNodeJunctionType,
|
||||
JunctionType toNodeJunctionType,
|
||||
@@ -518,14 +518,16 @@ namespace Serein.NodeFlow.Env
|
||||
return await currentFlowEnvironment.SetStartNodeAsync(canvasGuid, nodeGuid);
|
||||
}
|
||||
|
||||
public async Task<bool> StartFlowAsync()
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
return await currentFlowEnvironment.StartFlowAsync();
|
||||
return await currentFlowEnvironment.StartFlowAsync(canvasGuids);
|
||||
}
|
||||
|
||||
public async Task<bool> StartAsyncInSelectNode(string startNodeGuid)
|
||||
|
||||
|
||||
public async Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
|
||||
{
|
||||
return await currentFlowEnvironment.StartAsyncInSelectNode(startNodeGuid);
|
||||
return await currentFlowEnvironment.StartFlowFromSelectNodeAsync(startNodeGuid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -173,10 +173,10 @@ namespace Serein.NodeFlow.Env
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlow)]
|
||||
private async Task<object> StartAsync()
|
||||
private async Task<object> StartAsync(string[] canvasGuid)
|
||||
{
|
||||
var uiContextOperation = environment.IOC.Get<UIContextOperation>();
|
||||
var state = await environment.StartFlowAsync();
|
||||
var state = await environment.StartFlowAsync(canvasGuid);
|
||||
return new
|
||||
{
|
||||
state = state,
|
||||
@@ -191,7 +191,7 @@ namespace Serein.NodeFlow.Env
|
||||
[AutoSocketHandle(ThemeValue = EnvMsgTheme.StartFlowInSelectNode)]
|
||||
private async Task<object> StartAsyncInSelectNode(string nodeGuid)
|
||||
{
|
||||
var state = await environment.StartAsyncInSelectNode(nodeGuid);
|
||||
var state = await environment.StartFlowFromSelectNodeAsync(nodeGuid);
|
||||
return new
|
||||
{
|
||||
state = state,
|
||||
|
||||
@@ -420,18 +420,22 @@ namespace Serein.NodeFlow.Env
|
||||
/// 启动远程环境的流程
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> StartFlowAsync()
|
||||
public async Task<bool> StartFlowAsync(string[] canvasGuids)
|
||||
{
|
||||
// 远程环境下不需要UI上下文
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.StartFlow);
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.StartFlow, new
|
||||
{
|
||||
canvasGuids
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从选定的节点开始运行
|
||||
/// </summary>
|
||||
/// <param name="startNodeGuid"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> StartAsyncInSelectNode(string startNodeGuid)
|
||||
public async Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
|
||||
{
|
||||
var result = await msgClient.SendAndWaitDataAsync<bool>(EnvMsgTheme.StartFlowInSelectNode, new
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化啊
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> RunAsync(CancellationToken token)
|
||||
@@ -85,22 +85,19 @@ namespace Serein.NodeFlow
|
||||
var flowNodes = flow.GetNodes();
|
||||
|
||||
// 找到流程的起始节点,开始运行
|
||||
NodeModelBase? startNode = flowNodes.FirstOrDefault(node => node.IsStart);
|
||||
if (startNode is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
NodeModelBase startNode = flow.GetStartNode();
|
||||
// 是否后台运行当前画布流程
|
||||
if (flow.IsTaskAsync)
|
||||
{
|
||||
_ = Task.Run(async () => await CallStartNode(startNode));
|
||||
_ = Task.Run(async () => await CallStartNode(startNode), token); // 后台调用流程中的触发器
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
await CallStartNode(startNode);
|
||||
|
||||
}
|
||||
var flipflopTasks = CallFlipflopNode(flow); // 获取所有触发器异步任务
|
||||
_ = Task.Run(async () => await flipflopTasks); // 后台调用流程中的触发器
|
||||
_ = Task.Run(async () => await CallFlipflopNode(flow), token); // 后台调用流程中的触发器
|
||||
}
|
||||
|
||||
// 等待流程运行完成
|
||||
@@ -226,7 +223,7 @@ namespace Serein.NodeFlow
|
||||
return isSuccessful;
|
||||
}
|
||||
|
||||
private Task CallFlipflopNode(FlowTask flow)
|
||||
private async Task CallFlipflopNode(FlowTask flow)
|
||||
{
|
||||
var env = WorkOptions.Environment;
|
||||
var flipflopNodes = flow.GetNodes().Where(item => item is SingleFlipflopNode node
|
||||
@@ -242,9 +239,8 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
await RunGlobalFlipflopAsync(env, node); // 启动流程时启动全局触发器
|
||||
});
|
||||
Task.WhenAll(tasks);
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -257,6 +253,7 @@ namespace Serein.NodeFlow
|
||||
var pool = WorkOptions.FlowContextPool;
|
||||
var token = WorkOptions.CancellationTokenSource.Token;
|
||||
var context = pool.Allocate();
|
||||
context.Reset();
|
||||
await startNode.StartFlowAsync(context, token);
|
||||
context.Exit();
|
||||
pool.Free(context);
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Serein.NodeFlow
|
||||
/// <summary>
|
||||
/// 上下文线程池
|
||||
/// </summary>
|
||||
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
|
||||
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每个画布需要启用的节点
|
||||
|
||||
@@ -69,6 +69,11 @@ namespace Serein.NodeFlow.Tool
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, $"尝试加载Dll时失败,路径不存在。{path}");
|
||||
return;
|
||||
}
|
||||
foreach (var file in Directory.GetFiles(path, "*.dll"))
|
||||
{
|
||||
LoadWindowsLibrarie(file);
|
||||
|
||||
@@ -23,6 +23,11 @@ namespace Serein.Workbench.Api
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据
|
||||
/// </summary>
|
||||
FlowCanvasDetails Model { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 移除节点
|
||||
/// </summary>
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
xmlns:view="clr-namespace:Serein.Workbench.Views"
|
||||
StartupUri="Views/FlowWorkbenchView.xaml"
|
||||
Startup="Application_Startup">
|
||||
<!--StartupUri="Views/FlowWorkbenchView.xaml"-->
|
||||
<!--StartupUri="MainWindow.xaml"-->
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
@@ -10,6 +10,7 @@ using Serein.Workbench.ViewModels;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Serein.Workbench
|
||||
@@ -38,10 +39,9 @@ namespace Serein.Workbench
|
||||
public static void AddWorkbenchServices(this IServiceCollection collection)
|
||||
{
|
||||
collection.AddSingleton<IFlowEEForwardingService, FlowEEForwardingService>(); // 流程事件管理
|
||||
collection.AddSingleton<IKeyEventService, KeyEventService>();// 按键事件管理
|
||||
collection.AddSingleton<IWorkbenchEventService, WorkbenchEventService>(); // 流程事件管理
|
||||
collection.AddSingleton<FlowNodeService>(); // 节点操作管理
|
||||
// collection.AddSingleton<IKeyEventService, KeyEventService>(); // 按键事件管理
|
||||
//collection.AddSingleton<FlowNodeControlService>(); // 流程节点控件管理
|
||||
}
|
||||
|
||||
|
||||
@@ -87,27 +87,30 @@ namespace Serein.Workbench
|
||||
{
|
||||
return ServiceProvider?.GetService<T>() ?? throw new NullReferenceException();
|
||||
}
|
||||
|
||||
|
||||
public App()
|
||||
{
|
||||
|
||||
var collection = new ServiceCollection();
|
||||
collection.AddWorkbenchServices();
|
||||
collection.AddFlowServices();
|
||||
collection.AddViewModelServices();
|
||||
var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口
|
||||
App.ServiceProvider = services;
|
||||
#if DEBUG
|
||||
|
||||
|
||||
|
||||
|
||||
_ = this.LoadLocalProjectAsync();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task LoadLocalProjectAsync()
|
||||
{
|
||||
await Task.Delay(500);
|
||||
#if DEBUG
|
||||
if (1 == 10)
|
||||
if (1 ==1)
|
||||
{
|
||||
// 这里是测试代码,可以删除
|
||||
string filePath;
|
||||
@@ -115,12 +118,17 @@ namespace Serein.Workbench
|
||||
filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\Release\banyunqi\project.dnf";
|
||||
filePath = @"F:\临时\project\project.dnf";
|
||||
filePath = @"F:\TempFile\flow\qrcode\project.dnf";
|
||||
//filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\test.dnf";
|
||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||
var dir = Path.GetDirectoryName(filePath);
|
||||
App.GetService<IFlowEnvironment>().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath);
|
||||
filePath = @"F:\TempFile\flow\temp\project.dnf";
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath)!; // filePath;//
|
||||
var dir = Path.GetDirectoryName(filePath);
|
||||
App.GetService<IFlowEnvironment>().LoadProject(new FlowEnvInfo { Project = App.FlowProjectData }, App.FileDataPath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
<converter:CountToVisibilityConverter x:Key="CountToVisibilityConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ListBox ItemsSource="{Binding Nodes}"
|
||||
Visibility="{Binding Nodes, Converter={StaticResource CountToVisibilityConverter}}"
|
||||
Background="{Binding BackgroundColor}">
|
||||
<ListBox ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||||
Visibility="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource CountToVisibilityConverter}}"
|
||||
Background="{Binding Background, RelativeSource={RelativeSource AncestorType=UserControl}}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="2">
|
||||
<Grid Margin="2" MouseLeftButtonDown="Grid_MouseLeftButtonDown" MouseMove="Grid_MouseMove" DataContext="{Binding}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding NodeType}"></TextBlock>
|
||||
<TextBlock Text="{Binding AnotherName}" Margin="4,0,0,0"></TextBlock>
|
||||
<TextBlock Text="{Binding MethodName}" Margin="6,0,0,0"></TextBlock>
|
||||
<TextBlock Text="{Binding NodeType}"/>
|
||||
<TextBlock Text="{Binding MethodAnotherName}" Margin="4,0,0,0"/>
|
||||
<TextBlock Text="{Binding MethodName}" Margin="6,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Workbench.Models;
|
||||
using System;
|
||||
using System.Collections;
|
||||
@@ -20,10 +21,19 @@ using System.Windows.Shapes;
|
||||
namespace Serein.Workbench.Customs
|
||||
{
|
||||
|
||||
|
||||
public class Test: DependencyObject
|
||||
/// <summary>
|
||||
/// 拖拽创建节点类型
|
||||
/// </summary>
|
||||
public static class MouseNodeType
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 创建来自DLL的节点
|
||||
/// </summary>
|
||||
public static string CreateDllNodeInCanvas { get; } = nameof(CreateDllNodeInCanvas);
|
||||
/// <summary>
|
||||
/// 创建基础节点
|
||||
/// </summary>
|
||||
public static string CreateBaseNodeInCanvas { get; } = nameof(CreateBaseNodeInCanvas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,66 +45,90 @@ namespace Serein.Workbench.Customs
|
||||
|
||||
public FlowMethodInfoListBox()
|
||||
{
|
||||
this.DataContext = this;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<FlowLibraryMethodDetailsInfo> Nodes
|
||||
public static readonly DependencyProperty ItemsSourceProperty =
|
||||
DependencyProperty.Register(nameof(ItemsSource), typeof(IEnumerable), typeof(FlowMethodInfoListBox), new PropertyMetadata(null));
|
||||
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get { return (IEnumerable<FlowLibraryMethodDetailsInfo>)GetValue(NodesProperty); }
|
||||
set { SetValue(NodesProperty, value); }
|
||||
get => (IEnumerable)GetValue(ItemsSourceProperty);
|
||||
set => SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
|
||||
//public ItemCollection Items
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return (ItemCollection)GetValue(ItemsProperty);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// SetValue(ItemsProperty, value);
|
||||
// }
|
||||
//}
|
||||
public static readonly DependencyProperty BackgroundProperty =
|
||||
DependencyProperty.Register(nameof(Background), typeof(Brush), typeof(FlowMethodInfoListBox), new PropertyMetadata(Brushes.Transparent));
|
||||
|
||||
|
||||
public static readonly DependencyProperty NodesProperty = DependencyProperty.Register("NodesProperty", typeof(IEnumerable<FlowLibraryMethodDetailsInfo>), typeof(FlowMethodInfoListBox));
|
||||
|
||||
//public int TurnValue
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return (int)GetValue(TurnValueProperty);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// SetValue(TurnValueProperty, value);
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
// public static readonly DependencyProperty NodesProperty = DependencyProperty.Register(nameof(Nodes), typeof(IEnumerable<FlowLibraryMethodDetailsInfo>), typeof(FlowMethodInfoListBox), new PropertyMetadata(null));
|
||||
|
||||
public Brush BackgroundColor
|
||||
public Brush Background
|
||||
{
|
||||
get { return (Brush)GetValue(BackgroundColorProperty); }
|
||||
set { SetValue(BackgroundColorProperty, value); }
|
||||
get => (Brush)GetValue(BackgroundProperty);
|
||||
set => SetValue(BackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BackgroundColorProperty =
|
||||
DependencyProperty.Register(nameof(BackgroundColor), typeof(Brush), typeof(FlowMethodInfoListBox), new PropertyMetadata(Brushes.White));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 存储拖拽开始时的鼠标位置
|
||||
/// </summary>
|
||||
private Point _dragStartPoint;
|
||||
|
||||
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
|
||||
// 记录鼠标按下时的位置
|
||||
_dragStartPoint = e.GetPosition(null);
|
||||
}
|
||||
|
||||
private void Grid_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
// 获取当前鼠标位置
|
||||
Point mousePos = e.GetPosition(null);
|
||||
// 计算鼠标移动的距离
|
||||
Vector diff = _dragStartPoint - mousePos;
|
||||
|
||||
// 判断是否符合拖拽的最小距离要求
|
||||
if (e.LeftButton == MouseButtonState.Pressed &&
|
||||
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
||||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
|
||||
{
|
||||
// 获取触发事件的 TextBlock
|
||||
|
||||
if (sender is Grid grid && grid.DataContext is MethodDetailsInfo mdInfo)
|
||||
{
|
||||
if (!EnumHelper.TryConvertEnum<Library.NodeType>(mdInfo.NodeType, out var nodeType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MoveNodeModel moveNodeModel = new MoveNodeModel()
|
||||
{
|
||||
NodeControlType = nodeType switch
|
||||
{
|
||||
NodeType.Action => NodeControlType.Action,
|
||||
NodeType.Flipflop => NodeControlType.Flipflop,
|
||||
NodeType.UI => NodeControlType.UI,
|
||||
_ => NodeControlType.None,
|
||||
},
|
||||
MethodDetailsInfo = mdInfo
|
||||
};
|
||||
//MoveNodeData moveNodeData = new MoveNodeData
|
||||
//{
|
||||
|
||||
|
||||
// MethodDetailsInfo = mdInfo,
|
||||
//};
|
||||
if (moveNodeModel.NodeControlType == NodeControlType.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建一个 DataObject 用于拖拽操作,并设置拖拽效果
|
||||
DataObject dragData = new DataObject(MouseNodeType.CreateDllNodeInCanvas, moveNodeModel);
|
||||
DragDrop.DoDragDrop(grid, dragData, DragDropEffects.Move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ namespace Serein.Workbench
|
||||
/// </summary>
|
||||
public partial class LogWindow : Window
|
||||
{
|
||||
private static LogWindow instance = new LogWindow();
|
||||
public static LogWindow Instance => instance;
|
||||
|
||||
|
||||
private StringBuilder logBuffer = new StringBuilder();
|
||||
private int logUpdateInterval = 200; // 批量更新的时间间隔(毫秒)
|
||||
private Timer logUpdateTimer;
|
||||
|
||||
@@ -9,6 +9,7 @@ using Serein.NodeFlow.Env;
|
||||
using Serein.NodeFlow.Tool;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Extension;
|
||||
using Serein.Workbench.Models;
|
||||
using Serein.Workbench.Node;
|
||||
using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
@@ -27,20 +28,7 @@ using DataObject = System.Windows.DataObject;
|
||||
|
||||
namespace Serein.Workbench
|
||||
{
|
||||
/// <summary>
|
||||
/// 拖拽创建节点类型
|
||||
/// </summary>
|
||||
public static class MouseNodeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建来自DLL的节点
|
||||
/// </summary>
|
||||
public static string CreateDllNodeInCanvas { get; } = nameof(CreateDllNodeInCanvas);
|
||||
/// <summary>
|
||||
/// 创建基础节点
|
||||
/// </summary>
|
||||
public static string CreateBaseNodeInCanvas { get; } = nameof(CreateBaseNodeInCanvas);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1257,6 +1245,7 @@ namespace Serein.Workbench
|
||||
#endregion
|
||||
|
||||
#region 拖拽DLL文件到左侧功能区,加载相关节点清单
|
||||
|
||||
/// <summary>
|
||||
/// 当拖动文件到窗口时触发,加载DLL文件
|
||||
/// </summary>
|
||||
@@ -1308,6 +1297,7 @@ namespace Serein.Workbench
|
||||
/// </summary>
|
||||
private void FlowChartCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
dynamic GlobalJunctionData = "";
|
||||
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
||||
if (myData.IsCreateing && e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
@@ -1406,12 +1396,12 @@ namespace Serein.Workbench
|
||||
PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y);
|
||||
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas))
|
||||
{
|
||||
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData)
|
||||
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeModel moveModel)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
||||
await EnvDecorator.CreateNodeAsync("MainCanvas", nodeData.NodeControlType, position, nodeData.MethodDetailsInfo); // 创建DLL文件的节点对象
|
||||
await EnvDecorator.CreateNodeAsync("MainCanvas", moveModel.NodeControlType, position, moveModel.MethodDetailsInfo); // 创建DLL文件的节点对象
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1704,7 +1694,8 @@ namespace Serein.Workbench
|
||||
Mouse.OverrideCursor = null; // 恢复视觉效果
|
||||
ViewModel.IsConnectionArgSourceNode = false;
|
||||
ViewModel.IsConnectionInvokeNode = false;
|
||||
GlobalJunctionData.OK();
|
||||
dynamic GlobalJunctionData = "";
|
||||
|
||||
}
|
||||
|
||||
#region 拖动画布实现缩放平移效果
|
||||
@@ -1908,6 +1899,8 @@ namespace Serein.Workbench
|
||||
/// <param name="e"></param>
|
||||
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
dynamic GlobalJunctionData = "";
|
||||
|
||||
if (GlobalJunctionData.MyGlobalConnectingData.IsCreateing)
|
||||
{
|
||||
return;
|
||||
@@ -1963,6 +1956,7 @@ namespace Serein.Workbench
|
||||
FlowChartCanvas.ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
dynamic GlobalJunctionData = "";
|
||||
// 创建连线
|
||||
if (GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing)
|
||||
{
|
||||
@@ -2818,8 +2812,9 @@ public class FlowLibrary
|
||||
CancelSelectNode();
|
||||
EndConnection();
|
||||
}
|
||||
dynamic GlobalJunctionData = "";
|
||||
|
||||
if(GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing)
|
||||
if (GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing)
|
||||
{
|
||||
if(myData.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
|
||||
@@ -9,21 +9,10 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Models
|
||||
{
|
||||
public partial class FlowLibraryMethodDetailsInfo(MethodDetailsInfo info): ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string _anotherName = info.MethodAnotherName;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _assmblyName = info.AssemblyName;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _methodName = info.MethodName;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _nodeType = info.NodeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 依赖信息
|
||||
/// </summary>
|
||||
internal partial class FlowLibraryInfo : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
@@ -33,12 +22,11 @@ namespace Serein.Workbench.Models
|
||||
private string _libraryName;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<FlowLibraryMethodDetailsInfo> _methodInfo;
|
||||
private ObservableCollection<MethodDetailsInfo> _methodInfo;
|
||||
|
||||
|
||||
public List<FlowLibraryMethodDetailsInfo> ActionNodes { get => MethodInfo.Where(x => x.NodeType == NodeType.Action.ToString()).ToList(); set { } }
|
||||
public List<FlowLibraryMethodDetailsInfo> FlipflopNodes { get => MethodInfo.Where(x => x.NodeType == NodeType.Flipflop.ToString()).ToList(); set { } }
|
||||
public List<FlowLibraryMethodDetailsInfo> UINodes { get => MethodInfo.Where(x => x.NodeType == NodeType.UI.ToString()).ToList(); set { } }
|
||||
public List<MethodDetailsInfo> ActionNodes { get => MethodInfo.Where(x => x.NodeType == NodeType.Action.ToString()).ToList(); set { } }
|
||||
public List<MethodDetailsInfo> FlipflopNodes { get => MethodInfo.Where(x => x.NodeType == NodeType.Flipflop.ToString()).ToList(); set { } }
|
||||
public List<MethodDetailsInfo> UINodes { get => MethodInfo.Where(x => x.NodeType == NodeType.UI.ToString()).ToList(); set { } }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
18
Workbench/Models/MoveNodeModel.cs
Normal file
18
Workbench/Models/MoveNodeModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Serein.Library;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Workbench.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 拖拽创建节点使用的数据
|
||||
/// </summary>
|
||||
internal class MoveNodeModel
|
||||
{
|
||||
public NodeControlType NodeControlType { get; set; }
|
||||
public MethodDetailsInfo MethodDetailsInfo { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,15 @@ using System.Windows.Shapes;
|
||||
using System.Windows.Media.Media3D;
|
||||
using System.Windows.Documents;
|
||||
using System.Threading;
|
||||
using Serein.Workbench.Services;
|
||||
using Serein.Workbench.Tool;
|
||||
|
||||
namespace Serein.Workbench.Node.View
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 控制带的拓展方法
|
||||
/// </summary>
|
||||
internal static class MyUIFunc
|
||||
{
|
||||
public static Pen CreateAndFreezePen()
|
||||
@@ -31,10 +37,11 @@ namespace Serein.Workbench.Node.View
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入参控件
|
||||
/// </summary>
|
||||
public class ParamsArgControl: Shape
|
||||
{
|
||||
|
||||
|
||||
public ParamsArgControl()
|
||||
{
|
||||
this.MouseDown += ParamsArg_OnMouseDown; // 增加或删除
|
||||
@@ -159,8 +166,10 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
public abstract class JunctionControlBase : Shape
|
||||
{
|
||||
private readonly FlowNodeService flowNodeService;
|
||||
protected JunctionControlBase()
|
||||
{
|
||||
flowNodeService = App.GetService<FlowNodeService>();
|
||||
this.Width = 25;
|
||||
this.Height = 20;
|
||||
this.MouseDown += JunctionControlBase_MouseDown;
|
||||
@@ -229,7 +238,7 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
if(_isMouseOver != value)
|
||||
{
|
||||
GlobalJunctionData.MyGlobalConnectingData.CurrentJunction = this;
|
||||
flowNodeService.ConnectingData.CurrentJunction = this;
|
||||
_isMouseOver = value;
|
||||
InvalidateVisual();
|
||||
}
|
||||
@@ -252,22 +261,22 @@ namespace Serein.Workbench.Node.View
|
||||
/// <returns></returns>
|
||||
protected Brush GetBackgrounp()
|
||||
{
|
||||
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
||||
if(!myData.IsCreateing)
|
||||
var cd = flowNodeService.ConnectingData;
|
||||
if(!cd.IsCreateing)
|
||||
{
|
||||
return Brushes.Transparent;
|
||||
}
|
||||
if (IsMouseOver)
|
||||
{
|
||||
if (myData.IsCanConnected)
|
||||
if (cd.IsCanConnected)
|
||||
{
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
if (cd.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
return myData.ConnectionInvokeType.ToLineColor();
|
||||
return cd.ConnectionInvokeType.ToLineColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
return myData.ConnectionArgSourceType.ToLineColor();
|
||||
return cd.ConnectionArgSourceType.ToLineColor();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -320,15 +329,15 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
var canvas = MainWindow.GetParentOfType<Canvas>(this);
|
||||
var canvas = WpfFuncTool.GetParentOfType<Canvas>(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 cd = flowNodeService.ConnectingData;
|
||||
cd.Reset();
|
||||
cd.IsCreateing = true; // 表示开始连接
|
||||
cd.StartJunction = this;
|
||||
cd.CurrentJunction = this;
|
||||
cd.StartPoint = this.TranslatePoint(new Point(this.Width / 2, this.Height / 2), canvas);
|
||||
|
||||
var junctionOfConnectionType = this.JunctionType.ToConnectyionType();
|
||||
ConnectionLineShape bezierLine; // 类别
|
||||
@@ -346,13 +355,13 @@ namespace Serein.Workbench.Node.View
|
||||
return;
|
||||
}
|
||||
bezierLine = new ConnectionLineShape(LineType.Bezier,
|
||||
myData.StartPoint,
|
||||
myData.StartPoint,
|
||||
cd.StartPoint,
|
||||
cd.StartPoint,
|
||||
brushColor,
|
||||
isTop: true); // 绘制临时的线
|
||||
|
||||
Mouse.OverrideCursor = Cursors.Cross; // 设置鼠标为正在创建连线
|
||||
myData.MyLine = new MyLine(canvas, bezierLine);
|
||||
cd.MyLine = new MyLine(canvas, bezierLine);
|
||||
}
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Serein.Workbench.Node.View
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置
|
||||
/// 重置连线状态
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
@@ -139,7 +139,7 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
}
|
||||
|
||||
public static class GlobalJunctionData
|
||||
public static class GlobalJunctionData1
|
||||
{
|
||||
//private static ConnectingData? myGlobalData;
|
||||
//private static object _lockObj = new object();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Workbench.Extension;
|
||||
using Serein.Workbench.Tool;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Windows;
|
||||
@@ -224,8 +225,8 @@ namespace Serein.Workbench.Node.View
|
||||
private void ConfigureLineContextMenu()
|
||||
{
|
||||
var contextMenu = new ContextMenu();
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem("删除连线", (s, e) => Remote()));
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem("于父节点调用顺序中置顶", (s, e) => Topping()));
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除连线", (s, e) => Remote()));
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("于父节点调用顺序中置顶", (s, e) => Topping()));
|
||||
BezierLine.ContextMenu = contextMenu;
|
||||
}
|
||||
|
||||
|
||||
@@ -140,26 +140,26 @@ namespace Serein.Workbench.Node.View
|
||||
return;
|
||||
}
|
||||
|
||||
MoveNodeData moveNodeData = new MoveNodeData
|
||||
{
|
||||
//MoveNodeData moveNodeData = new MoveNodeData
|
||||
//{
|
||||
|
||||
NodeControlType = nodeType switch
|
||||
{
|
||||
NodeType.Action => NodeControlType.Action,
|
||||
NodeType.Flipflop => NodeControlType.Flipflop,
|
||||
NodeType.UI => NodeControlType.UI,
|
||||
_ => NodeControlType.None,
|
||||
},
|
||||
MethodDetailsInfo = mdInfo,
|
||||
};
|
||||
if(moveNodeData.NodeControlType == NodeControlType.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// NodeControlType = nodeType switch
|
||||
// {
|
||||
// NodeType.Action => NodeControlType.Action,
|
||||
// NodeType.Flipflop => NodeControlType.Flipflop,
|
||||
// NodeType.UI => NodeControlType.UI,
|
||||
// _ => NodeControlType.None,
|
||||
// },
|
||||
// MethodDetailsInfo = mdInfo,
|
||||
//};
|
||||
//if(moveNodeData.NodeControlType == NodeControlType.None)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// 创建一个 DataObject 用于拖拽操作,并设置拖拽效果
|
||||
DataObject dragData = new DataObject(MouseNodeType.CreateDllNodeInCanvas, moveNodeData);
|
||||
DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move);
|
||||
//// 创建一个 DataObject 用于拖拽操作,并设置拖拽效果
|
||||
//DataObject dragData = new DataObject(MouseNodeType.CreateDllNodeInCanvas, moveNodeData);
|
||||
//DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="MainWindow.xaml.cs" />
|
||||
<Compile Remove="MainWindowViewModel.cs" />
|
||||
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
|
||||
<Compile Remove="Node\INodeContainerControl.cs" />
|
||||
<Compile Remove="Node\Junction\NodeJunctionViewBase.cs" />
|
||||
@@ -38,6 +40,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="MainWindow.xaml" />
|
||||
<Page Remove="Node\FlipflopRegionControl.xaml" />
|
||||
<Page Remove="Node\View\ActionRegionControl.xaml" />
|
||||
<Page Remove="Themes\ConditionControl.xaml" />
|
||||
|
||||
@@ -26,17 +26,21 @@ namespace Serein.Workbench.Services
|
||||
/// </summary>
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
private readonly IFlowEnvironmentEvent flowEnvironmentEvent;
|
||||
private readonly UIContextOperation uIContextOperation;
|
||||
|
||||
/// <summary>
|
||||
/// 转发流程运行环境各个事件的实现类
|
||||
/// </summary>
|
||||
/// <param name="flowEnvironment"></param>
|
||||
/// <param name="flowEnvironmentEvent"></param>
|
||||
/// <param name="uIContextOperation"></param>
|
||||
public FlowEEForwardingService(IFlowEnvironment flowEnvironment,
|
||||
IFlowEnvironmentEvent flowEnvironmentEvent)
|
||||
IFlowEnvironmentEvent flowEnvironmentEvent,
|
||||
UIContextOperation uIContextOperation)
|
||||
{
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
this.flowEnvironmentEvent = flowEnvironmentEvent;
|
||||
this.uIContextOperation = uIContextOperation;
|
||||
InitFlowEnvironmentEvent();
|
||||
}
|
||||
|
||||
@@ -185,7 +189,10 @@ namespace Serein.Workbench.Services
|
||||
/// <param name="value"></param>
|
||||
private void FlowEnvironment_OnEnvOutEvent(InfoType type, string value)
|
||||
{
|
||||
//LogOutWindow.AppendText($"{DateTime.Now} [{type}] : {value}{Environment.NewLine}");
|
||||
uIContextOperation.Invoke(() =>
|
||||
{
|
||||
OnEnvOut?.Invoke(type, value);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Serein.Library;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Node;
|
||||
@@ -6,7 +8,10 @@ using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using Serein.Workbench.Views;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Serein.Workbench.Services
|
||||
{
|
||||
@@ -34,7 +39,6 @@ namespace Serein.Workbench.Services
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 创建节点相关的属性
|
||||
/// <summary>
|
||||
/// 当前查看的画布
|
||||
@@ -51,7 +55,6 @@ namespace Serein.Workbench.Services
|
||||
/// </summary>
|
||||
public NodeControlType CurrentNodeControlType { get; set; } = NodeControlType.None;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当前鼠标位置
|
||||
/// </summary>
|
||||
@@ -61,6 +64,12 @@ namespace Serein.Workbench.Services
|
||||
/// 当前选中的节点
|
||||
/// </summary>
|
||||
public NodeControlBase? CurrentSelectNodeControl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接数据
|
||||
/// </summary>
|
||||
public ConnectingData ConnectingData { get; } = new ConnectingData();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -72,6 +81,11 @@ namespace Serein.Workbench.Services
|
||||
/// </summary>
|
||||
public NodeControlBase? ConnectionEndNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前所有画布
|
||||
/// </summary>
|
||||
public FlowCanvasView[] FlowCanvass => Canvass.Select(c => c.Value).ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// 记录流程画布
|
||||
/// </summary>
|
||||
@@ -134,7 +148,27 @@ namespace Serein.Workbench.Services
|
||||
flowEEForwardingService.OnNodeTakeOut += FlowEEForwardingService_OnNodeTakeOut; ; // 节点从容器中取出
|
||||
|
||||
flowEEForwardingService.OnNodeConnectChange += FlowEEForwardingService_OnNodeConnectChange; // 节点连接状态改变事件
|
||||
|
||||
|
||||
flowEEForwardingService.OnStartNodeChange += FlowEEForwardingService_OnStartNodeChange; // 画布起始节点改变
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void FlowEEForwardingService_OnStartNodeChange(StartNodeChangeEventArgs eventArgs)
|
||||
{
|
||||
string oldNodeGuid = eventArgs.OldNodeGuid;
|
||||
string newNodeGuid = eventArgs.NewNodeGuid;
|
||||
if (!TryGetControl(newNodeGuid, out var newStartNodeControl)) return;
|
||||
if (!string.IsNullOrEmpty(oldNodeGuid))
|
||||
{
|
||||
if (!TryGetControl(oldNodeGuid, out var oldStartNodeControl)) return;
|
||||
oldStartNodeControl.BorderBrush = Brushes.Black;
|
||||
oldStartNodeControl.BorderThickness = new Thickness(0);
|
||||
}
|
||||
|
||||
newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
||||
newStartNodeControl.BorderThickness = new Thickness(2);
|
||||
var node = newStartNodeControl?.ViewModel?.NodeModel;
|
||||
}
|
||||
|
||||
private void FlowEEForwardingService_OnNodeConnectChange(NodeConnectChangeEventArgs e)
|
||||
@@ -387,7 +421,167 @@ namespace Serein.Workbench.Services
|
||||
return Canvass.TryGetValue(nodeGuid, out flowCanvas);
|
||||
}
|
||||
|
||||
#region 节点的复制与粘贴
|
||||
/// <summary>
|
||||
/// 从节点信息转换为Json文本数据
|
||||
/// </summary>
|
||||
public string CpoyNodeInfo(List<NodeModelBase> dictSelection)
|
||||
{
|
||||
|
||||
// 遍历当前已选节点
|
||||
foreach (var node in dictSelection.ToArray())
|
||||
{
|
||||
if (node.ChildrenNode.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 遍历这些节点的子节点,添加过来
|
||||
foreach (var childNode in node.ChildrenNode)
|
||||
{
|
||||
dictSelection.Add(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
var nodeInfos = dictSelection.Select(item => item.ToInfo());
|
||||
|
||||
JObject json = new JObject()
|
||||
{
|
||||
["nodes"] = JArray.FromObject(nodeInfos)
|
||||
};
|
||||
|
||||
var jsonText = json.ToString();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, $"复制已选节点({dictSelection.Count}个)");
|
||||
return jsonText;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, $"复制失败:{ex.Message}");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从Json中加载节点
|
||||
/// </summary>
|
||||
/// <param name="canvasGuid">需要加载在哪个画布上</param>
|
||||
/// <param name="jsonText">文本内容</param>
|
||||
/// <param name="positionOfUI">需要加载的位置</param>
|
||||
public void PasteNodeInfo(string canvasGuid, string jsonText, PositionOfUI positionOfUI)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<NodeInfo>? nodes = JsonConvert.DeserializeObject<List<NodeInfo>>(jsonText);
|
||||
if (nodes is not null && nodes.Count != 0)
|
||||
{
|
||||
|
||||
}
|
||||
if (nodes is null || nodes.Count < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#region 节点去重
|
||||
Dictionary<string, string> guids = new Dictionary<string, string>(); // 记录 Guid
|
||||
|
||||
// 遍历当前节点
|
||||
foreach (var node in nodes.ToArray())
|
||||
{
|
||||
if (NodeControls.ContainsKey(node.Guid) && !guids.ContainsKey(node.Guid))
|
||||
{
|
||||
// 如果是没出现过、且在当前记录中重复的Guid,则记录并新增对应的映射。
|
||||
guids.TryAdd(node.Guid, Guid.NewGuid().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// 出现过的Guid,说明重复添加了。应该不会走到这。
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node.ChildNodeGuids is null)
|
||||
{
|
||||
continue; // 跳过没有子节点的节点
|
||||
}
|
||||
|
||||
// 遍历这些节点的子节点,获得完整的已选节点信息
|
||||
foreach (var childNodeGuid in node.ChildNodeGuids)
|
||||
{
|
||||
if (NodeControls.ContainsKey(node.Guid) && !NodeControls.ContainsKey(node.Guid))
|
||||
{
|
||||
// 当前Guid并不重复,跳过替换
|
||||
continue;
|
||||
}
|
||||
if (!guids.ContainsKey(childNodeGuid))
|
||||
{
|
||||
// 如果是没出现过的Guid,则记录并新增对应的映射。
|
||||
guids.TryAdd(node.Guid, Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(childNodeGuid)
|
||||
&& NodeControls.TryGetValue(childNodeGuid, out var nodeControl))
|
||||
{
|
||||
|
||||
var newNodeInfo = nodeControl.ViewModel.NodeModel.ToInfo();
|
||||
nodes.Add(newNodeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Guid去重
|
||||
StringBuilder sb = new StringBuilder(jsonText);
|
||||
foreach (var kv in guids)
|
||||
{
|
||||
sb.Replace(kv.Key, kv.Value);
|
||||
}
|
||||
string result = sb.ToString();
|
||||
|
||||
/*var replacer = new GuidReplacer();
|
||||
foreach (var kv in guids)
|
||||
{
|
||||
replacer.AddReplacement(kv.Key, kv.Value);
|
||||
}
|
||||
string result = replacer.Replace(jsonText);*/
|
||||
|
||||
|
||||
//SereinEnv.WriteLine(InfoType.ERROR, result);
|
||||
nodes = JsonConvert.DeserializeObject<List<NodeInfo>>(result);
|
||||
|
||||
if (nodes is null || nodes.Count < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// 获取第一个节点的原始位置
|
||||
var index0NodeX = nodes[0].Position.X;
|
||||
var index0NodeY = nodes[0].Position.Y;
|
||||
|
||||
// 计算所有节点相对于第一个节点的偏移量
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
node.CanvasGuid = canvasGuid; // 替换画布Guid
|
||||
|
||||
var offsetX = node.Position.X - index0NodeX;
|
||||
var offsetY = node.Position.Y - index0NodeY;
|
||||
|
||||
// 根据鼠标位置平移节点
|
||||
node.Position = new PositionOfUI(positionOfUI.X + offsetX, positionOfUI.Y + offsetY);
|
||||
}
|
||||
|
||||
_ = flowEnvironment.LoadNodeInfosAsync(nodes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
//SereinEnv.WriteLine(InfoType.ERROR, $"粘贴节点时发生异常:{ex}");
|
||||
}
|
||||
// SereinEnv.WriteLine(InfoType.INFO, $"剪贴板文本内容: {clipboardText}");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 向运行环境发出请求
|
||||
|
||||
|
||||
@@ -6,19 +6,20 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using static System.Windows.Forms.AxHost;
|
||||
|
||||
namespace Serein.Workbench.Services
|
||||
{
|
||||
delegate void KeyDownEventHandler(Key key);
|
||||
delegate void KeyUpEventHandler(Key key);
|
||||
public delegate void KeyDownEventHandler(Key key);
|
||||
public delegate void KeyUpEventHandler(Key key);
|
||||
|
||||
/// <summary>
|
||||
/// 全局事件服务
|
||||
/// 全局按键事件服务
|
||||
/// </summary>
|
||||
internal interface IKeyEventService
|
||||
public interface IKeyEventService
|
||||
{
|
||||
event KeyDownEventHandler KeyDown;
|
||||
event KeyUpEventHandler KeyUp;
|
||||
event KeyDownEventHandler OnKeyDown;
|
||||
event KeyUpEventHandler OnKeyUp;
|
||||
|
||||
/// <summary>
|
||||
/// 获取某个按键状态
|
||||
@@ -26,27 +27,34 @@ namespace Serein.Workbench.Services
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
bool GetKeyState(Key key);
|
||||
|
||||
/// <summary>
|
||||
/// 设置某个按键的状态
|
||||
/// 按下了某个键
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="state"></param>
|
||||
void SetKeyState(Key key, bool statestate);
|
||||
void KeyDown(Key key);
|
||||
|
||||
/// <summary>
|
||||
/// 抬起了某个键
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
void KeyUp(Key key);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 管理按键状态
|
||||
/// </summary>
|
||||
internal class KeyEventService : IKeyEventService
|
||||
public class KeyEventService : IKeyEventService
|
||||
{
|
||||
/// <summary>
|
||||
/// 按键按下
|
||||
/// </summary>
|
||||
public event KeyDownEventHandler KeyDown;
|
||||
public event KeyDownEventHandler OnKeyDown;
|
||||
/// <summary>
|
||||
/// 按键松开
|
||||
/// </summary>
|
||||
public event KeyUpEventHandler KeyUp;
|
||||
public event KeyUpEventHandler OnKeyUp;
|
||||
|
||||
public KeyEventService()
|
||||
{
|
||||
@@ -62,18 +70,23 @@ namespace Serein.Workbench.Services
|
||||
{
|
||||
return KeysState[(int)key];
|
||||
}
|
||||
public void SetKeyState(Key key, bool state)
|
||||
|
||||
|
||||
|
||||
|
||||
public void KeyDown(Key key)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
KeyDown?.Invoke(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyUp?.Invoke(key);
|
||||
}
|
||||
//Debug.WriteLine($"按键事件:{key} - {state}");
|
||||
KeysState[(int)key] = state;
|
||||
KeysState[(int)key] = true;
|
||||
OnKeyDown?.Invoke(key);
|
||||
Debug.WriteLine($"按键按下事件:{key}");
|
||||
}
|
||||
|
||||
public void KeyUp(Key key)
|
||||
{
|
||||
KeysState[(int)key] = false;
|
||||
OnKeyUp?.Invoke(key);
|
||||
Debug.WriteLine($"按键抬起事件:{key}");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow;
|
||||
using Serein.NodeFlow.Env;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Node;
|
||||
using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
|
||||
|
||||
namespace Serein.Workbench.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点操作相关服务
|
||||
/// </summary>
|
||||
internal class NodeControlService
|
||||
{
|
||||
|
||||
public NodeControlService(IFlowEnvironment flowEnvironment,
|
||||
IFlowEEForwardingService feefService)
|
||||
{
|
||||
/* this.flowEnvironment = flowEnvironment;
|
||||
this.feefService = feefService;
|
||||
feefService.OnNodeCreate += FeefService_OnNodeCreate; // 订阅运行环境创建节点事件
|
||||
feefService.OnNodeConnectChange += FeefService_OnNodeConnectChange; // 订阅运行环境连接了节点事件
|
||||
// 手动加载项目
|
||||
_ = Task.Run(async delegate
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
var flowEnvironment = new FlowEnvironment();// App.GetService<IFlowEnvironment>();
|
||||
var filePath = @"C:\Users\Az\source\repos\CLBanyunqiState\CLBanyunqiState\bin\debug\net8.0\project.dnf";
|
||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||
var projectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||
var projectDfilePath = System.IO.Path.GetDirectoryName(filePath)!;
|
||||
flowEnvironment.LoadProject(new FlowEnvInfo { Project = projectData }, projectDfilePath);
|
||||
}, CancellationToken.None);*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -71,9 +72,15 @@ namespace Serein.Workbench.Services
|
||||
private void InitEvents()
|
||||
{
|
||||
flowEEForwardingService.OnProjectSaving += SaveProjectToLocalFile;
|
||||
flowEEForwardingService.OnEnvOut += FlowEEForwardingService_OnEnvOut;
|
||||
}
|
||||
|
||||
|
||||
private void FlowEEForwardingService_OnEnvOut(InfoType type, string value)
|
||||
{
|
||||
LogWindow.Instance.AppendText($"{DateTime.Now} [{type}] : {value}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 预览了某个方法信息(待创建)
|
||||
@@ -103,6 +110,8 @@ namespace Serein.Workbench.Services
|
||||
private void SaveProjectToLocalFile(ProjectSavingEventArgs e)
|
||||
{
|
||||
var project = e.ProjectData;
|
||||
|
||||
#region 获取保存路径
|
||||
// 创建一个新的保存文件对话框
|
||||
SaveFileDialog saveFileDialog = new()
|
||||
{
|
||||
@@ -128,8 +137,10 @@ namespace Serein.Workbench.Services
|
||||
SereinEnv.WriteLine(InfoType.ERROR, "保存项目DLL时返回了意外的文件保存路径");
|
||||
return;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 将Dll输出到指定路径
|
||||
Uri saveProjectFileUri = new Uri(savePath);
|
||||
SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath);
|
||||
for (int index = 0; index < project.Librarys.Length; index++)
|
||||
@@ -180,12 +191,104 @@ namespace Serein.Workbench.Services
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 输出项目保存文件
|
||||
JObject projectJsonData = JObject.FromObject(project);
|
||||
File.WriteAllText(savePath, projectJsonData.ToString());
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region 抽取重复文件(例如net运行时)
|
||||
/*
|
||||
|
||||
1. 扫描目录并计算哈希
|
||||
string[] directories = new[] { "path1", "path2" };
|
||||
var fileHashMap = new Dictionary<string, List<string>>(); // hash -> List<full paths>
|
||||
|
||||
foreach (var dir in directories)
|
||||
{
|
||||
foreach (var file in Directory.EnumerateFiles(dir, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
using var stream = File.OpenRead(file);
|
||||
using var sha = SHA256.Create();
|
||||
var hash = Convert.ToHexString(sha.ComputeHash(stream));
|
||||
|
||||
if (!fileHashMap.ContainsKey(hash))
|
||||
fileHashMap[hash] = new List<string>();
|
||||
|
||||
fileHashMap[hash].Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
2. 将重复文件压缩并保存
|
||||
string archiveDir = "compressed_output";
|
||||
Directory.CreateDirectory(archiveDir);
|
||||
|
||||
var manifest = new List<FileRecord>();
|
||||
|
||||
foreach (var kvp in fileHashMap.Where(kvp => kvp.Value.Count > 1))
|
||||
{
|
||||
var hash = kvp.Key;
|
||||
var originalFile = kvp.Value[0];
|
||||
var archivePath = Path.Combine(archiveDir, $"{hash}.gz");
|
||||
|
||||
using (var input = File.OpenRead(originalFile))
|
||||
using (var output = File.Create(archivePath))
|
||||
using (var gzip = new GZipStream(output, CompressionLevel.Optimal))
|
||||
{
|
||||
input.CopyTo(gzip);
|
||||
}
|
||||
|
||||
manifest.Add(new FileRecord
|
||||
{
|
||||
Hash = hash,
|
||||
ArchiveFile = $"{hash}.gz",
|
||||
OriginalPaths = kvp.Value
|
||||
});
|
||||
}
|
||||
|
||||
3. 生成清单文件(JSON)
|
||||
public class FileRecord
|
||||
{
|
||||
public string Hash { get; set; }
|
||||
public string ArchiveFile { get; set; }
|
||||
public List<string> OriginalPaths { get; set; }
|
||||
}
|
||||
|
||||
File.WriteAllText("manifest.json", JsonSerializer.Serialize(manifest, new JsonSerializerOptions { WriteIndented = true }));
|
||||
|
||||
|
||||
4. 根据清单还原原始文件结构
|
||||
var manifestJson = File.ReadAllText("manifest.json");
|
||||
var manifest = JsonSerializer.Deserialize<List<FileRecord>>(manifestJson);
|
||||
|
||||
foreach (var record in manifest)
|
||||
{
|
||||
var archivePath = Path.Combine("compressed_output", record.ArchiveFile);
|
||||
|
||||
foreach (var path in record.OriginalPaths)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||
|
||||
using var input = File.OpenRead(archivePath);
|
||||
using var gzip = new GZipStream(input, CompressionMode.Decompress);
|
||||
using var output = File.Create(path);
|
||||
|
||||
gzip.CopyTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Workbench.Tool;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
@@ -137,11 +138,11 @@ namespace Serein.Workbench.Themes
|
||||
treeViewItem.Expanded += TreeViewItem_Expanded;
|
||||
|
||||
var contextMenu = new ContextMenu();
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem("从此节点执行", async (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("从此节点执行", async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await flowEnvironment.StartAsyncInSelectNode(tmpNodeTreeModel.RootNode.Guid);
|
||||
await flowEnvironment.StartFlowFromSelectNodeAsync(tmpNodeTreeModel.RootNode.Guid);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -149,7 +150,7 @@ namespace Serein.Workbench.Themes
|
||||
return;
|
||||
}
|
||||
}));
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem("定位", (s, e) => flowEnvironment.NodeLocated(tmpNodeTreeModel.RootNode.Guid)));
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("定位", (s, e) => flowEnvironment.NodeLocated(tmpNodeTreeModel.RootNode.Guid)));
|
||||
|
||||
treeViewItem.ContextMenu = contextMenu;
|
||||
treeViewItem.Margin = new Thickness(-20, 0, 0, 0);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils.SereinExpression;
|
||||
using Serein.Workbench.Tool;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@@ -294,7 +295,7 @@ namespace Serein.Workbench.Themes
|
||||
|
||||
// 配置右键菜单
|
||||
var contextMenu = new ContextMenu();
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem($"表达式", (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem($"表达式", (s, e) =>
|
||||
{
|
||||
ExpressionTextBox.Text = subPath; // 获取表达式
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Serein.Workbench.Tool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -165,7 +166,7 @@ namespace Serein.Workbench.Themes
|
||||
{
|
||||
isChange = true;
|
||||
contextMenu = new ContextMenu();
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem($"取值表达式", (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem($"取值表达式", (s, e) =>
|
||||
{
|
||||
string fullPath = GetNodeFullPath(memberNode);
|
||||
string copyValue = "@Get " + fullPath;
|
||||
@@ -181,7 +182,7 @@ namespace Serein.Workbench.Themes
|
||||
{
|
||||
isChange = true;
|
||||
contextMenu = new ContextMenu();
|
||||
contextMenu.Items.Add(MainWindow.CreateMenuItem($"取值表达式", (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem($"取值表达式", (s, e) =>
|
||||
{
|
||||
string fullPath = GetNodeFullPath(memberNode);
|
||||
string copyValue = "@Get " + fullPath;
|
||||
|
||||
48
Workbench/Tool/WpfFuncTool.cs
Normal file
48
Workbench/Tool/WpfFuncTool.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
|
||||
namespace Serein.Workbench.Tool
|
||||
{
|
||||
internal static class WpfFuncTool
|
||||
{ /// <summary>
|
||||
/// 创建菜单子项
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="handler"></param>
|
||||
/// <returns></returns>
|
||||
public static MenuItem CreateMenuItem(string header, RoutedEventHandler handler)
|
||||
{
|
||||
var menuItem = new MenuItem { Header = header };
|
||||
menuItem.Click += handler;
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 穿透元素获取区域容器
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
public static T? GetParentOfType<T>(DependencyObject element) where T : DependencyObject
|
||||
{
|
||||
while (element != null)
|
||||
{
|
||||
if (element is T e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
element = VisualTreeHelper.GetParent(element);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,9 @@ namespace Serein.Workbench.ViewModels
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 画布当前选中的节点
|
||||
/// 画布当前的节点
|
||||
/// </summary>
|
||||
public NodeControlBase CurrentSelectNode { get; set; }
|
||||
public Dictionary<string, NodeControlBase> NodeControls { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 正在创建节点方法调用关系
|
||||
|
||||
@@ -23,9 +23,6 @@ namespace Serein.Workbench.ViewModels
|
||||
public partial class FlowEditViewModel : ObservableObject
|
||||
{
|
||||
public ObservableCollection<FlowEditorTabModel> CanvasTabs { get; set; } = [];
|
||||
public ICommand AddTabCommand { get; set; }
|
||||
public ICommand RemoveTabCommand { get; set; }
|
||||
public ICommand RenameTabCommand { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -39,8 +36,7 @@ namespace Serein.Workbench.ViewModels
|
||||
public FlowEditViewModel(FlowNodeService flowNodeService)
|
||||
{
|
||||
this.flowNodeService = flowNodeService;
|
||||
AddTabCommand = new RelayCommand(AddTab);
|
||||
RemoveTabCommand = new RelayCommand(RemoveTab);
|
||||
|
||||
|
||||
flowNodeService.OnCreateFlowCanvasView += OnCreateFlowCanvasView; // 创建了画布
|
||||
flowNodeService.OnRemoveFlowCanvasView += OnRemoveFlowCanvasView; // 移除了画布
|
||||
@@ -81,13 +77,6 @@ namespace Serein.Workbench.ViewModels
|
||||
#endregion
|
||||
|
||||
|
||||
private void AddTab() => flowNodeService.CreateFlowCanvas();
|
||||
private void RemoveTab()
|
||||
{
|
||||
if (CanvasTabs.Count > 0 && SelectedTab != null) flowNodeService.RemoveFlowCanvas();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Env;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Models;
|
||||
using Serein.Workbench.Services;
|
||||
@@ -15,16 +17,33 @@ namespace Serein.Workbench.ViewModels
|
||||
internal partial class FlowLibrarysViewModel : ObservableObject
|
||||
{
|
||||
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<FlowLibraryInfo> flowLibraryInfos;
|
||||
|
||||
public FlowLibrarysViewModel(IFlowEEForwardingService flowEEForwardingService)
|
||||
public FlowLibrarysViewModel(IFlowEEForwardingService flowEEForwardingService,IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
this.flowEEForwardingService = flowEEForwardingService;
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
FlowLibraryInfos = new ObservableCollection<FlowLibraryInfo>();
|
||||
flowEEForwardingService.OnDllLoad += FlowEEForwardingService_OnDllLoad;
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载文件依赖
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public void LoadFileLibrary(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
flowEnvironment.LoadLibrary(filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
flowEnvironment.WriteLine(Library.InfoType.ERROR, ex.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void FlowEEForwardingService_OnDllLoad(Library.Api.LoadDllEventArgs eventArgs)
|
||||
{
|
||||
@@ -32,10 +51,10 @@ namespace Serein.Workbench.ViewModels
|
||||
List<MethodDetailsInfo> mds = eventArgs.MethodDetailss;
|
||||
NodeLibraryInfo libraryInfo = eventArgs.NodeLibraryInfo;
|
||||
|
||||
var methodInfo = new ObservableCollection<FlowLibraryMethodDetailsInfo>();
|
||||
var methodInfo = new ObservableCollection<MethodDetailsInfo>();
|
||||
foreach (var md in mds)
|
||||
{
|
||||
methodInfo.Add(new FlowLibraryMethodDetailsInfo(md));
|
||||
methodInfo.Add(md);
|
||||
}
|
||||
var flInfo = new FlowLibraryInfo
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Env;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Models;
|
||||
using Serein.Workbench.Services;
|
||||
@@ -8,19 +10,36 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Serein.Workbench.ViewModels
|
||||
{
|
||||
internal partial class FlowWorkbenchViewModel : ObservableObject
|
||||
{
|
||||
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
private readonly IWorkbenchEventService workbenchEventService;
|
||||
private readonly IKeyEventService keyEventService;
|
||||
|
||||
public FlowWorkbenchViewModel(IFlowEEForwardingService flowEEForwardingService, IWorkbenchEventService workbenchEventService)
|
||||
public FlowWorkbenchViewModel(IFlowEnvironment flowEnvironment,
|
||||
IWorkbenchEventService workbenchEventService,
|
||||
IKeyEventService keyEventService)
|
||||
{
|
||||
this.flowEEForwardingService = flowEEForwardingService;
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
this.workbenchEventService = workbenchEventService;
|
||||
//flowEEForwardingService.OnDllLoad += FlowEEForwardingService_OnDllLoad;
|
||||
this.keyEventService = keyEventService;
|
||||
EventManager.RegisterClassHandler(typeof(Window), Keyboard.KeyDownEvent, new KeyEventHandler(OnKeyDown)); // 按下事件
|
||||
EventManager.RegisterClassHandler(typeof(Window), Keyboard.KeyUpEvent, new KeyEventHandler(OnKeyUp)); // 松开事件
|
||||
}
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
keyEventService.KeyDown(e.Key);
|
||||
}
|
||||
private void OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
keyEventService.KeyUp(e.Key);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Workbench.Services;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Serein.Workbench.ViewModels
|
||||
@@ -8,6 +9,7 @@ namespace Serein.Workbench.ViewModels
|
||||
public class MainMenuBarViewModel : ObservableObject
|
||||
{
|
||||
private readonly IFlowEnvironment environment;
|
||||
private readonly FlowNodeService flowNodeService;
|
||||
|
||||
/// <summary>
|
||||
/// 保存项目
|
||||
@@ -31,6 +33,10 @@ namespace Serein.Workbench.ViewModels
|
||||
/// </summary>
|
||||
public ICommand RemoteFlowCanvasCommand { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运行当前画布流程
|
||||
/// </summary>
|
||||
public ICommand StartFlowCommand { get; private set; }
|
||||
/// <summary>
|
||||
/// 运行当前画布流程
|
||||
/// </summary>
|
||||
@@ -55,10 +61,10 @@ namespace Serein.Workbench.ViewModels
|
||||
|
||||
|
||||
|
||||
public MainMenuBarViewModel(IFlowEnvironment environment)
|
||||
public MainMenuBarViewModel(IFlowEnvironment environment, FlowNodeService flowNodeService)
|
||||
{
|
||||
this.environment = environment;
|
||||
|
||||
this.flowNodeService = flowNodeService;
|
||||
SaveProjectCommand = new RelayCommand(SaveProject); // 保存项目
|
||||
LoadLocalProjectCommand = new RelayCommand(LoadLocalProject); // 加载本地项目
|
||||
LoadRemoteProjectCommand = new RelayCommand(LoadRemoteProject); // 加载远程项目
|
||||
@@ -66,26 +72,30 @@ namespace Serein.Workbench.ViewModels
|
||||
CreateFlowCanvasCommand = new RelayCommand(CreateFlowCanvas); // 增加画布
|
||||
RemoteFlowCanvasCommand = new RelayCommand(RemoteFlowCanvas); // 移除画布
|
||||
|
||||
StartCurrentCanvasFlowCommand = new RelayCommand(StartCurrentCanvasFlow); // 运行当前流程
|
||||
StartFlowCommand = new RelayCommand(StartFlow);
|
||||
StartCurrentCanvasFlowCommand = new RelayCommand(StartCurrentCanvasFlow); // 运行当前所查看画布的流程
|
||||
StopCurrentCanvasFlowCommand = new RelayCommand(StopCurrentCanvasFlow); // 停止当前流程
|
||||
|
||||
OpenEnvOutWindowCommand = new RelayCommand(OpenEnvOutWindow); // 打开运行输出窗口
|
||||
OpenDynamicCompilerCommand = new RelayCommand(OpenDynamicCompiler); // 打开动态编译仓库窗口
|
||||
}
|
||||
|
||||
private void SaveProject() {
|
||||
environment.SaveProject(); // 保存项目
|
||||
}
|
||||
private void SaveProject() => environment.SaveProject(); // 保存项目
|
||||
private void LoadLocalProject() {
|
||||
//environment.LoadProject(); // 加载项目
|
||||
}
|
||||
private void LoadRemoteProject() { }
|
||||
private void CreateFlowCanvas() { }
|
||||
private void RemoteFlowCanvas() { }
|
||||
private void StartCurrentCanvasFlow() { }
|
||||
private void LoadRemoteProject()
|
||||
{
|
||||
}
|
||||
private void CreateFlowCanvas() => flowNodeService.CreateFlowCanvas();
|
||||
|
||||
private void RemoteFlowCanvas() => flowNodeService.RemoveFlowCanvas();
|
||||
|
||||
private void StartFlow() => environment.StartFlowAsync([.. flowNodeService.FlowCanvass.Select(c => c.Guid)]);
|
||||
private void StartCurrentCanvasFlow() => environment.StartFlowAsync([flowNodeService.CurrentSelectCanvas.Guid]);
|
||||
private void StopCurrentCanvasFlow() { }
|
||||
private void OpenDynamicCompiler() { }
|
||||
private void OpenEnvOutWindow() { }
|
||||
private void OpenEnvOutWindow() => LogWindow.Instance?.Show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Serein.Workbench.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows;
|
||||
|
||||
namespace Serein.Workbench.ViewModels
|
||||
{
|
||||
public class MainViewModel : ObservableObject
|
||||
{
|
||||
public MainViewModel()
|
||||
private readonly IKeyEventService keyEventService;
|
||||
|
||||
public MainViewModel(IKeyEventService keyEventService)
|
||||
{
|
||||
|
||||
this.keyEventService = keyEventService;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Library;
|
||||
using Serein.Workbench.Customs;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<Canvas ClipToBounds="True"
|
||||
x:Name="FlowChartCanvas"
|
||||
Background="#E1FBEA"
|
||||
Background="#FFFFFF"
|
||||
AllowDrop="True"
|
||||
Width="{Binding Model.Width, Mode=TwoWay}"
|
||||
Height="{Binding Model.Height, Mode=TwoWay}"
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
using Serein.Library;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Env;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Customs;
|
||||
using Serein.Workbench.Extension;
|
||||
using Serein.Workbench.Models;
|
||||
using Serein.Workbench.Node;
|
||||
using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Services;
|
||||
using Serein.Workbench.Themes;
|
||||
using Serein.Workbench.Tool;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Drawing.Printing;
|
||||
using System.Linq;
|
||||
@@ -19,13 +26,20 @@ using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media.Media3D;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using static Serein.Workbench.MainWindow;
|
||||
using Binding = System.Windows.Data.Binding;
|
||||
using DragDropEffects = System.Windows.DragDropEffects;
|
||||
using DragEventArgs = System.Windows.DragEventArgs;
|
||||
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
|
||||
using UserControl = System.Windows.Controls.UserControl;
|
||||
using Clipboard = System.Windows.Clipboard;
|
||||
using TextDataFormat = System.Windows.TextDataFormat;
|
||||
|
||||
namespace Serein.Workbench.Views
|
||||
{
|
||||
@@ -34,9 +48,11 @@ namespace Serein.Workbench.Views
|
||||
/// </summary>
|
||||
public partial class FlowCanvasView : UserControl, IFlowCanvas
|
||||
{
|
||||
|
||||
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
private readonly IKeyEventService keyEventService;
|
||||
private readonly FlowNodeService flowNodeService;
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有的连接。考虑集成在运行环境中。
|
||||
/// </summary>
|
||||
@@ -44,7 +60,6 @@ namespace Serein.Workbench.Views
|
||||
|
||||
private FlowCanvasViewModel ViewModel => this.DataContext as FlowCanvasViewModel ?? throw new ArgumentNullException();
|
||||
|
||||
|
||||
#region 画布接口实现
|
||||
private IFlowCanvas Api => this;
|
||||
|
||||
@@ -57,9 +72,10 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
|
||||
public string Name => ViewModel.Model.Name;
|
||||
|
||||
FlowCanvasDetails IFlowCanvas.Model => ViewModel.Model;
|
||||
void IFlowCanvas.Remove(NodeControlBase nodeControl)
|
||||
{
|
||||
ViewModel.NodeControls.Remove(nodeControl.ViewModel.NodeModel.Guid);
|
||||
FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
{
|
||||
FlowChartCanvas.Children.Remove(nodeControl);
|
||||
@@ -67,11 +83,15 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
void IFlowCanvas.Add(NodeControlBase nodeControl)
|
||||
{
|
||||
ViewModel.NodeControls.TryAdd(nodeControl.ViewModel.NodeModel.Guid, nodeControl);
|
||||
FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
{
|
||||
FlowChartCanvas.Children.Add(nodeControl);
|
||||
});
|
||||
|
||||
ConfigureNodeEvents(nodeControl); // 配置相关事件
|
||||
ConfigureContextMenu(nodeControl); // 添加右键菜单
|
||||
|
||||
}
|
||||
|
||||
void IFlowCanvas.CreateInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, ConnectionInvokeType type)
|
||||
@@ -224,6 +244,9 @@ namespace Serein.Workbench.Views
|
||||
/// 标记是否正在拖动画布
|
||||
/// </summary>
|
||||
private bool IsCanvasDragging;
|
||||
/// <summary>
|
||||
/// 是否正在选取控件
|
||||
/// </summary>
|
||||
private bool IsSelectDragging;
|
||||
|
||||
/// <summary>
|
||||
@@ -258,8 +281,7 @@ namespace Serein.Workbench.Views
|
||||
private readonly TranslateTransform translateTransform;
|
||||
#endregion
|
||||
|
||||
|
||||
#region 初始化
|
||||
#region 初始化以及相关事件
|
||||
|
||||
public FlowCanvasView(FlowCanvasDetails model)
|
||||
{
|
||||
@@ -270,9 +292,9 @@ namespace Serein.Workbench.Views
|
||||
|
||||
flowEnvironment = App.GetService<IFlowEnvironment>();
|
||||
flowNodeService = App.GetService<FlowNodeService>();
|
||||
|
||||
keyEventService = App.GetService<IKeyEventService>();
|
||||
flowNodeService.OnCreateNode += OnCreateNode;
|
||||
|
||||
keyEventService.OnKeyDown += KeyEventService_OnKeyDown; ;
|
||||
|
||||
// 缩放平移容器
|
||||
canvasTransformGroup = new TransformGroup();
|
||||
@@ -286,6 +308,10 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置绑定
|
||||
/// </summary>
|
||||
/// <param name="canvasModel"></param>
|
||||
private void SetBinding(FlowCanvasDetails canvasModel)
|
||||
{
|
||||
Binding bindingScaleX = new(nameof(canvasModel.ScaleX)) { Source = canvasModel, Mode = BindingMode.TwoWay };
|
||||
@@ -325,8 +351,7 @@ namespace Serein.Workbench.Views
|
||||
{
|
||||
// 并非添加在容器中,直接放置节点
|
||||
Api.Add(nodeControl); // 添加到对应的画布上
|
||||
ConfigureNodeEvents(nodeControl); // 添加了节点
|
||||
ConfigureContextMenu(nodeControl); // 添加右键菜单
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -349,7 +374,7 @@ namespace Serein.Workbench.Views
|
||||
// 准备放置条件表达式控件
|
||||
if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.ExpCondition)
|
||||
{
|
||||
ConditionRegionControl? conditionRegion = GetParentOfType<ConditionRegionControl>(hitElement);
|
||||
ConditionRegionControl? conditionRegion = WpfFuncTool.GetParentOfType<ConditionRegionControl>(hitElement);
|
||||
if (conditionRegion is not null)
|
||||
{
|
||||
targetNodeControl = conditionRegion;
|
||||
@@ -362,7 +387,7 @@ namespace Serein.Workbench.Views
|
||||
else
|
||||
{
|
||||
// 准备放置全局数据控件
|
||||
GlobalDataControl? globalDataControl = GetParentOfType<GlobalDataControl>(hitElement);
|
||||
GlobalDataControl? globalDataControl = WpfFuncTool.GetParentOfType<GlobalDataControl>(hitElement);
|
||||
if (globalDataControl is not null)
|
||||
{
|
||||
targetNodeControl = globalDataControl;
|
||||
@@ -376,6 +401,107 @@ namespace Serein.Workbench.Views
|
||||
|
||||
#endregion
|
||||
|
||||
#region 画布键盘操作
|
||||
/// <summary>
|
||||
/// 监听按键事件
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
private void KeyEventService_OnKeyDown(Key key)
|
||||
{
|
||||
if (!flowNodeService.CurrentSelectCanvas.Guid.Equals(Guid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == Key.Escape)
|
||||
{
|
||||
IsControlDragging = false;
|
||||
IsCanvasDragging = false;
|
||||
SelectionRectangle.Visibility = Visibility.Collapsed;
|
||||
CancelSelectNode();
|
||||
EndConnection();
|
||||
return;
|
||||
}
|
||||
|
||||
// 复制节点
|
||||
if (selectNodeControls.Count > 0 && key == Key.C && (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl)))
|
||||
{
|
||||
var text = flowNodeService.CpoyNodeInfo([.. selectNodeControls.Select(c => c.ViewModel.NodeModel)]);
|
||||
Clipboard.SetDataObject(text, true); // 复制,持久性设置
|
||||
return;
|
||||
}
|
||||
|
||||
// 粘贴节点
|
||||
if (key == Key.V && (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl)))
|
||||
{
|
||||
string clipboardText = Clipboard.GetText(TextDataFormat.Text); // 获取复制的文本
|
||||
var jobject = JObject.Parse(clipboardText);
|
||||
var nodesText = jobject["nodes"]?.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(nodesText))
|
||||
{
|
||||
|
||||
if (Clipboard.ContainsText())
|
||||
{
|
||||
Point mousePosition = Mouse.GetPosition(FlowChartCanvas);
|
||||
PositionOfUI positionOfUI = new PositionOfUI(mousePosition.X, mousePosition.Y); // 坐标数据
|
||||
flowNodeService.PasteNodeInfo(Guid, nodesText, positionOfUI); // 粘贴节点信息
|
||||
}
|
||||
else if (Clipboard.ContainsImage())
|
||||
{
|
||||
// var image = Clipboard.GetImage();
|
||||
}
|
||||
else
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "剪贴板中没有可识别的数据。");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var cd = flowNodeService.ConnectingData;
|
||||
if (cd.IsCreateing)
|
||||
{
|
||||
if (cd.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
ConnectionInvokeType connectionInvokeType = key switch
|
||||
{
|
||||
Key.D1 => ConnectionInvokeType.Upstream,
|
||||
Key.D2 => ConnectionInvokeType.IsSucceed,
|
||||
Key.D3 => ConnectionInvokeType.IsFail,
|
||||
Key.D4 => ConnectionInvokeType.IsError,
|
||||
_ => ConnectionInvokeType.None,
|
||||
};
|
||||
|
||||
if (connectionInvokeType != ConnectionInvokeType.None)
|
||||
{
|
||||
cd.ConnectionInvokeType = connectionInvokeType;
|
||||
cd.MyLine.Line.UpdateLineColor(connectionInvokeType.ToLineColor());
|
||||
}
|
||||
}
|
||||
else if (cd.Type == JunctionOfConnectionType.Arg)
|
||||
{
|
||||
ConnectionArgSourceType connectionArgSourceType = key switch
|
||||
{
|
||||
Key.D1 => ConnectionArgSourceType.GetOtherNodeData,
|
||||
Key.D2 => ConnectionArgSourceType.GetOtherNodeDataOfInvoke,
|
||||
_ => ConnectionArgSourceType.GetPreviousNodeData,
|
||||
};
|
||||
|
||||
if (connectionArgSourceType != ConnectionArgSourceType.GetPreviousNodeData)
|
||||
{
|
||||
cd.ConnectionArgSourceType = connectionArgSourceType;
|
||||
cd.MyLine.Line.UpdateLineColor(connectionArgSourceType.ToLineColor());
|
||||
}
|
||||
}
|
||||
cd.CurrentJunction.InvalidateVisual(); // 刷新目标节点控制点样式
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 画布鼠标操作
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 鼠标在画布移动。
|
||||
@@ -385,11 +511,11 @@ namespace Serein.Workbench.Views
|
||||
/// </summary>
|
||||
private void FlowChartCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
var myData = GlobalJunctionData.MyGlobalConnectingData;
|
||||
if (myData.IsCreateing && e.LeftButton == MouseButtonState.Pressed)
|
||||
var cd = flowNodeService.ConnectingData;
|
||||
if (cd.IsCreateing && e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
if (cd.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
ViewModel.IsConnectionInvokeNode = true; // 正在连接节点的调用关系
|
||||
|
||||
@@ -401,7 +527,7 @@ namespace Serein.Workbench.Views
|
||||
var currentPoint = e.GetPosition(FlowChartCanvas);
|
||||
currentPoint.X -= 2;
|
||||
currentPoint.Y -= 2;
|
||||
myData.UpdatePoint(currentPoint);
|
||||
cd.UpdatePoint(currentPoint);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -456,10 +582,10 @@ namespace Serein.Workbench.Views
|
||||
PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y);
|
||||
if (e.Data.GetDataPresent(MouseNodeType.CreateDllNodeInCanvas))
|
||||
{
|
||||
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeData nodeData)
|
||||
if (e.Data.GetData(MouseNodeType.CreateDllNodeInCanvas) is MoveNodeModel nodeModel)
|
||||
{
|
||||
flowNodeService.CurrentNodeControlType = nodeData.NodeControlType; // 设置基础节点类型
|
||||
flowNodeService.CurrentDragMdInfo = nodeData.MethodDetailsInfo; // 基础节点不需要参数信息
|
||||
flowNodeService.CurrentNodeControlType = nodeModel.NodeControlType; // 设置基础节点类型
|
||||
flowNodeService.CurrentDragMdInfo = nodeModel.MethodDetailsInfo; // 基础节点不需要参数信息
|
||||
flowNodeService.CurrentMouseLocation = position; // 设置当前鼠标为止
|
||||
flowNodeService.CreateNode(); // 创建来自DLL加载的方法节点
|
||||
}
|
||||
@@ -524,7 +650,8 @@ namespace Serein.Workbench.Views
|
||||
/// <param name="e"></param>
|
||||
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (GlobalJunctionData.MyGlobalConnectingData.IsCreateing)
|
||||
|
||||
if (flowNodeService.ConnectingData.IsCreateing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -580,42 +707,42 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
|
||||
// 创建连线
|
||||
if (GlobalJunctionData.MyGlobalConnectingData is ConnectingData myData && myData.IsCreateing)
|
||||
var cd = flowNodeService.ConnectingData;
|
||||
if (cd.IsCreateing)
|
||||
{
|
||||
|
||||
if (myData.IsCanConnected)
|
||||
if (cd.IsCanConnected)
|
||||
{
|
||||
var canvas = this.FlowChartCanvas;
|
||||
var currentendPoint = e.GetPosition(canvas); // 当前鼠标落点
|
||||
var changingJunctionPosition = myData.CurrentJunction.TranslatePoint(new Point(0, 0), canvas);
|
||||
var changingJunctionRect = new Rect(changingJunctionPosition, new Size(myData.CurrentJunction.Width, myData.CurrentJunction.Height));
|
||||
var changingJunctionPosition = cd.CurrentJunction.TranslatePoint(new Point(0, 0), canvas);
|
||||
var changingJunctionRect = new Rect(changingJunctionPosition, new Size(cd.CurrentJunction.Width, cd.CurrentJunction.Height));
|
||||
|
||||
if (changingJunctionRect.Contains(currentendPoint)) // 可以创建连接
|
||||
{
|
||||
#region 方法调用关系创建
|
||||
if (myData.Type == JunctionOfConnectionType.Invoke)
|
||||
if (cd.Type == JunctionOfConnectionType.Invoke)
|
||||
{
|
||||
var canvasGuid = this.Guid;
|
||||
|
||||
await flowEnvironment.ConnectInvokeNodeAsync(
|
||||
canvasGuid,
|
||||
myData.StartJunction.MyNode.Guid,
|
||||
myData.CurrentJunction.MyNode.Guid,
|
||||
myData.StartJunction.JunctionType,
|
||||
myData.CurrentJunction.JunctionType,
|
||||
myData.ConnectionInvokeType);
|
||||
cd.StartJunction.MyNode.Guid,
|
||||
cd.CurrentJunction.MyNode.Guid,
|
||||
cd.StartJunction.JunctionType,
|
||||
cd.CurrentJunction.JunctionType,
|
||||
cd.ConnectionInvokeType);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 参数来源关系创建
|
||||
else if (myData.Type == JunctionOfConnectionType.Arg)
|
||||
else if (cd.Type == JunctionOfConnectionType.Arg)
|
||||
{
|
||||
var argIndex = 0;
|
||||
if (myData.StartJunction is ArgJunctionControl argJunction1)
|
||||
if (cd.StartJunction is ArgJunctionControl argJunction1)
|
||||
{
|
||||
argIndex = argJunction1.ArgIndex;
|
||||
}
|
||||
else if (myData.CurrentJunction is ArgJunctionControl argJunction2)
|
||||
else if (cd.CurrentJunction is ArgJunctionControl argJunction2)
|
||||
{
|
||||
argIndex = argJunction2.ArgIndex;
|
||||
}
|
||||
@@ -623,11 +750,11 @@ namespace Serein.Workbench.Views
|
||||
|
||||
await flowEnvironment.ConnectArgSourceNodeAsync(
|
||||
canvasGuid,
|
||||
myData.StartJunction.MyNode.Guid,
|
||||
myData.CurrentJunction.MyNode.Guid,
|
||||
myData.StartJunction.JunctionType,
|
||||
myData.CurrentJunction.JunctionType,
|
||||
myData.ConnectionArgSourceType,
|
||||
cd.StartJunction.MyNode.Guid,
|
||||
cd.CurrentJunction.MyNode.Guid,
|
||||
cd.StartJunction.JunctionType,
|
||||
cd.CurrentJunction.JunctionType,
|
||||
cd.ConnectionArgSourceType,
|
||||
argIndex);
|
||||
}
|
||||
#endregion
|
||||
@@ -640,7 +767,14 @@ namespace Serein.Workbench.Views
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region 拖动画布实现缩放平移效果
|
||||
|
||||
/// <summary>
|
||||
/// 开始拖动画布
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void FlowChartCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
IsCanvasDragging = true;
|
||||
@@ -649,11 +783,13 @@ namespace Serein.Workbench.Views
|
||||
e.Handled = true; // 防止事件传播影响其他控件
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止拖动
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void FlowChartCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
|
||||
|
||||
|
||||
if (IsCanvasDragging)
|
||||
{
|
||||
IsCanvasDragging = false;
|
||||
@@ -661,7 +797,11 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
}
|
||||
|
||||
// 单纯缩放画布,不改变画布大小
|
||||
/// <summary>
|
||||
/// 单纯缩放画布,不改变画布大小
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void FlowChartCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
// if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
@@ -820,6 +960,9 @@ namespace Serein.Workbench.Views
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 完成选取操作
|
||||
@@ -887,6 +1030,27 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void CancelSelectNode()
|
||||
{
|
||||
IsSelectControl = false;
|
||||
foreach (var nodeControl in selectNodeControls)
|
||||
{
|
||||
//nodeControl.ViewModel.IsSelect = false;
|
||||
nodeControl.BorderBrush = Brushes.Black;
|
||||
nodeControl.BorderThickness = new Thickness(0);
|
||||
|
||||
var startNodeGuid = ViewModel.Model.StartNode;
|
||||
var nodeGuid = nodeControl.ViewModel.NodeModel.Guid;
|
||||
if (startNodeGuid.Equals(nodeGuid))
|
||||
{
|
||||
nodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
||||
nodeControl.BorderThickness = new Thickness(2);
|
||||
}
|
||||
}
|
||||
selectNodeControls.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束连接操作,清理状态并移除虚线。
|
||||
/// </summary>
|
||||
@@ -895,21 +1059,9 @@ namespace Serein.Workbench.Views
|
||||
Mouse.OverrideCursor = null; // 恢复视觉效果
|
||||
ViewModel.IsConnectionArgSourceNode = false;
|
||||
ViewModel.IsConnectionInvokeNode = false;
|
||||
GlobalJunctionData.OK();
|
||||
flowNodeService.ConnectingData.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建菜单子项
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="handler"></param>
|
||||
/// <returns></returns>
|
||||
public static MenuItem CreateMenuItem(string header, RoutedEventHandler handler)
|
||||
{
|
||||
var menuItem = new MenuItem { Header = header };
|
||||
menuItem.Click += handler;
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选择范围配置
|
||||
@@ -918,7 +1070,7 @@ namespace Serein.Workbench.Views
|
||||
private ContextMenu ConfiguerSelectionRectangle()
|
||||
{
|
||||
var contextMenu = new ContextMenu();
|
||||
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", (s, e) =>
|
||||
{
|
||||
if (selectNodeControls.Count > 0)
|
||||
{
|
||||
@@ -938,6 +1090,10 @@ namespace Serein.Workbench.Views
|
||||
// nodeControl.ContextMenu = contextMenu;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 节点控件相关事件
|
||||
/// <summary>
|
||||
/// 配置节点事件(移动,点击相关)
|
||||
@@ -950,13 +1106,7 @@ namespace Serein.Workbench.Views
|
||||
nodeControl.MouseMove += Block_MouseMove;
|
||||
nodeControl.MouseLeftButtonUp += Block_MouseLeftButtonUp;
|
||||
|
||||
}
|
||||
private void EmptyNodeEvents(NodeControlBase nodeControl)
|
||||
{
|
||||
|
||||
nodeControl.MouseLeftButtonDown -= Block_MouseLeftButtonDown;
|
||||
nodeControl.MouseMove -= Block_MouseMove;
|
||||
nodeControl.MouseLeftButtonUp -= Block_MouseLeftButtonUp;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -972,8 +1122,8 @@ namespace Serein.Workbench.Views
|
||||
IsControlDragging = true;
|
||||
startControlDragPoint = e.GetPosition(FlowChartCanvas); // 记录鼠标按下时的位置
|
||||
((UIElement)sender).CaptureMouse(); // 捕获鼠标
|
||||
e.Handled = true; // 防止事件传播影响其他控件
|
||||
}
|
||||
e.Handled = true; // 防止事件传播影响其他控件
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -981,12 +1131,13 @@ namespace Serein.Workbench.Views
|
||||
/// </summary>
|
||||
private void Block_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
|
||||
if (IsCanvasDragging)
|
||||
return;
|
||||
if (IsSelectControl)
|
||||
return;
|
||||
|
||||
if (IsControlDragging) // 如果正在拖动控件
|
||||
if (IsControlDragging && !flowNodeService.ConnectingData.IsCreateing) // 如果正在拖动控件
|
||||
{
|
||||
Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置
|
||||
|
||||
@@ -1005,21 +1156,26 @@ namespace Serein.Workbench.Views
|
||||
var newLeft = oldLeft + deltaX;
|
||||
var newTop = oldTop + deltaY;
|
||||
|
||||
this.flowEnvironment.MoveNode(Guid, nodeControlMain.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
|
||||
|
||||
// 计算控件实际移动的距离
|
||||
var actualDeltaX = newLeft - oldLeft;
|
||||
var actualDeltaY = newTop - oldTop;
|
||||
|
||||
// 移动其它选中的控件
|
||||
foreach (var nodeControl in selectNodeControls)
|
||||
List<(string Guid, double NewLeft, double NewTop, double MaxWidth, double MaxHeight)> moveSizes =
|
||||
selectNodeControls.Select(control =>
|
||||
(control.ViewModel.NodeModel.Guid,
|
||||
Canvas.GetLeft(control) + actualDeltaX,
|
||||
Canvas.GetTop(control) + actualDeltaY,
|
||||
control.FlowCanvas.Model.Width - control.ActualWidth - 10,
|
||||
control.FlowCanvas.Model.Height - control.ActualHeight - 10)).ToList();
|
||||
|
||||
var isNeedCancel = moveSizes.Exists(item => item.NewLeft < 5 || item.NewTop < 5|| item.NewLeft > item.MaxWidth || item.NewTop > item.MaxHeight);
|
||||
if (isNeedCancel)
|
||||
{
|
||||
if (nodeControl != nodeControlMain) // 跳过已经移动的控件
|
||||
{
|
||||
var otherNewLeft = Canvas.GetLeft(nodeControl) + actualDeltaX;
|
||||
var otherNewTop = Canvas.GetTop(nodeControl) + actualDeltaY;
|
||||
this.flowEnvironment.MoveNode(Guid, nodeControl.ViewModel.NodeModel.Guid, otherNewLeft, otherNewTop); // 移动节点
|
||||
}
|
||||
return;
|
||||
}
|
||||
foreach (var item in moveSizes)
|
||||
{
|
||||
this.flowEnvironment.MoveNode(this.Guid, item.Guid, item.NewLeft, item.NewTop); // 移动节点
|
||||
}
|
||||
|
||||
// 更新节点之间线的连接位置
|
||||
@@ -1038,6 +1194,14 @@ namespace Serein.Workbench.Views
|
||||
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
|
||||
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // 新的左边距
|
||||
double newTop = Canvas.GetTop(nodeControl) + deltaY; // 新的上边距
|
||||
|
||||
// 如果被移动的控件接触到画布边缘,则限制移动范围
|
||||
var canvasModel = nodeControl.FlowCanvas.Model;
|
||||
var canvasWidth = canvasModel.Width - nodeControl.ActualWidth - 10;
|
||||
var canvasHeight= canvasModel.Height - nodeControl.ActualHeight - 10;
|
||||
newLeft = newLeft < 5 ? 5 : newLeft > canvasWidth ? canvasWidth : newLeft;
|
||||
newTop = newTop < 5 ? 5 : newTop > canvasHeight ? canvasHeight : newTop;
|
||||
|
||||
this.flowEnvironment.MoveNode(Guid, nodeControl.ViewModel.NodeModel.Guid, newLeft, newTop); // 移动节点
|
||||
nodeControl.UpdateLocationConnections();
|
||||
}
|
||||
@@ -1095,7 +1259,7 @@ namespace Serein.Workbench.Views
|
||||
|
||||
if (nodeControl.ViewModel?.NodeModel.ControlType == NodeControlType.Flipflop)
|
||||
{
|
||||
contextMenu.Items.Add(CreateMenuItem("启动触发器", (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("启动触发器", (s, e) =>
|
||||
{
|
||||
if (s is MenuItem menuItem)
|
||||
{
|
||||
@@ -1119,7 +1283,7 @@ namespace Serein.Workbench.Views
|
||||
|
||||
if (nodeControl.ViewModel?.NodeModel?.MethodDetails?.ReturnType is Type returnType && returnType != typeof(void))
|
||||
{
|
||||
contextMenu.Items.Add(CreateMenuItem("查看返回类型", (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("查看返回类型", (s, e) =>
|
||||
{
|
||||
DisplayReturnTypeTreeViewer(returnType);
|
||||
}));
|
||||
@@ -1127,8 +1291,8 @@ namespace Serein.Workbench.Views
|
||||
|
||||
|
||||
|
||||
contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => flowEnvironment.SetStartNodeAsync(canvasGuid, nodeGuid)));
|
||||
contextMenu.Items.Add(CreateMenuItem("删除", async (s, e) =>
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("设为起点", (s, e) => flowEnvironment.SetStartNodeAsync(canvasGuid, nodeGuid)));
|
||||
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", async (s, e) =>
|
||||
{
|
||||
var result = await flowEnvironment.RemoveNodeAsync(canvasGuid, nodeGuid);
|
||||
}));
|
||||
@@ -1136,28 +1300,28 @@ namespace Serein.Workbench.Views
|
||||
#region 右键菜单功能 - 控件对齐
|
||||
|
||||
var AvoidMenu = new MenuItem();
|
||||
AvoidMenu.Items.Add(CreateMenuItem("群组对齐", (s, e) =>
|
||||
AvoidMenu.Items.Add(WpfFuncTool.CreateMenuItem("群组对齐", (s, e) =>
|
||||
{
|
||||
AlignControlsWithGrouping(selectNodeControls, AlignMode.Grouping);
|
||||
}));
|
||||
AvoidMenu.Items.Add(CreateMenuItem("规划对齐", (s, e) =>
|
||||
AvoidMenu.Items.Add(WpfFuncTool.CreateMenuItem("规划对齐", (s, e) =>
|
||||
{
|
||||
AlignControlsWithGrouping(selectNodeControls, AlignMode.Planning);
|
||||
}));
|
||||
AvoidMenu.Items.Add(CreateMenuItem("水平中心对齐", (s, e) =>
|
||||
AvoidMenu.Items.Add(WpfFuncTool.CreateMenuItem("水平中心对齐", (s, e) =>
|
||||
{
|
||||
AlignControlsWithGrouping(selectNodeControls, AlignMode.HorizontalCenter);
|
||||
}));
|
||||
AvoidMenu.Items.Add(CreateMenuItem("垂直中心对齐 ", (s, e) =>
|
||||
AvoidMenu.Items.Add(WpfFuncTool.CreateMenuItem("垂直中心对齐 ", (s, e) =>
|
||||
{
|
||||
AlignControlsWithGrouping(selectNodeControls, AlignMode.VerticalCenter);
|
||||
}));
|
||||
|
||||
AvoidMenu.Items.Add(CreateMenuItem("垂直对齐时水平斜分布", (s, e) =>
|
||||
AvoidMenu.Items.Add(WpfFuncTool.CreateMenuItem("垂直对齐时水平斜分布", (s, e) =>
|
||||
{
|
||||
AlignControlsWithGrouping(selectNodeControls, AlignMode.Vertical);
|
||||
}));
|
||||
AvoidMenu.Items.Add(CreateMenuItem("水平对齐时垂直斜分布", (s, e) =>
|
||||
AvoidMenu.Items.Add(WpfFuncTool.CreateMenuItem("水平对齐时垂直斜分布", (s, e) =>
|
||||
{
|
||||
AlignControlsWithGrouping(selectNodeControls, AlignMode.Horizontal);
|
||||
}));
|
||||
|
||||
@@ -56,11 +56,11 @@ AllowDrop="True"-->
|
||||
</TabControl>
|
||||
|
||||
<!-- Tab control buttons -->
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right">
|
||||
<!--<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right">
|
||||
<Button Content="添加" Command="{Binding AddTabCommand}" Margin="5" Width="80"/>
|
||||
<Button Content="移除" Command="{Binding RemoveTabCommand}" Margin="5" Width="80"/>
|
||||
<!--<Button Content="Rename Tab" Command="{Binding RenameTabCommand}" />-->
|
||||
</StackPanel>
|
||||
--><!--<Button Content="Rename Tab" Command="{Binding RenameTabCommand}" />--><!--
|
||||
</StackPanel>-->
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
|
||||
@@ -126,12 +126,11 @@ namespace Serein.Workbench.Views
|
||||
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is TabControl tabControl
|
||||
&& tabControl.SelectedIndex > 0
|
||||
&& tabControl.SelectedIndex > -1
|
||||
&& DataContext is FlowEditViewModel viewModel
|
||||
&& viewModel.CanvasTabs[tabControl.SelectedIndex] is FlowEditorTabModel tab)
|
||||
{
|
||||
|
||||
viewModel.EndEditingTab(lastTab); // 确认新名称
|
||||
viewModel.EndEditingTab(lastTab); // 取消编辑
|
||||
lastTab = tab;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,24 @@
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance vm:FlowLibrarysViewModel}"
|
||||
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
AllowDrop="True"
|
||||
Drop="FlowLibrarysView_Drop"
|
||||
DragOver="FlowLibrarysView_DragOver" >
|
||||
|
||||
<UserControl.Resources>
|
||||
<converter:CountToVisibilityConverter x:Key="CountToVisibilityConverter"/>
|
||||
|
||||
|
||||
<!--<DataTemplate x:Key="NodeListTemplate">
|
||||
<Grid Margin="2">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding NodeType}"/>
|
||||
<TextBlock Text="{Binding AnotherName}" Margin="4,0,0,0"/>
|
||||
<TextBlock Text="{Binding MethodName}" Margin="6,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>-->
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer>
|
||||
@@ -31,58 +44,27 @@
|
||||
<TextBlock Text="{Binding LibraryName}" ></TextBlock>
|
||||
<TextBlock Text="{Binding FilePath}" Margin="6,0,0,0"></TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!--<custom:FlowMethodInfoListBox Grid.Row="1" Nodes="{Binding ActionNodes}" BackgroundColor="#D0F1F9"/>
|
||||
<custom:FlowMethodInfoListBox Grid.Row="2" Nodes="{Binding FlipflopNodes}" BackgroundColor="#FACFC1"/>
|
||||
<custom:FlowMethodInfoListBox Grid.Row="3" Nodes="{Binding UINodes}" BackgroundColor="#FFFBD7"/>-->
|
||||
|
||||
<ListBox Grid.Row="1" Margin="6,2,2,2" ItemsSource="{Binding ActionNodes}"
|
||||
<custom:FlowMethodInfoListBox Grid.Row="1" ItemsSource="{Binding ActionNodes}" Background="#D0F1F9"/>
|
||||
<custom:FlowMethodInfoListBox Grid.Row="2" ItemsSource="{Binding FlipflopNodes}" Background="#FACFC1"/>
|
||||
<custom:FlowMethodInfoListBox Grid.Row="3" ItemsSource="{Binding UINodes}" Background="#FFFBD7"/>
|
||||
|
||||
<!--<ListBox Grid.Row="1" Margin="6,2,2,2" ItemsSource="{Binding ActionNodes}"
|
||||
Visibility="{Binding ActionNodes, Converter={StaticResource CountToVisibilityConverter}}"
|
||||
Background="#D0F1F9">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="2" >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding NodeType}"></TextBlock>
|
||||
<TextBlock Text="{Binding AnotherName}" Margin="4,0,0,0"></TextBlock>
|
||||
<TextBlock Text="{Binding MethodName}" Margin="6,0,0,0"></TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
Background="#D0F1F9"
|
||||
ItemTemplate="{StaticResource NodeListTemplate}">
|
||||
</ListBox>
|
||||
|
||||
<ListBox Grid.Row="2" Margin="6,2,2,2" ItemsSource="{Binding FlipflopNodes}"
|
||||
Visibility="{Binding FlipflopNodes, Converter={StaticResource CountToVisibilityConverter}}"
|
||||
Background="#FACFC1">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="2" >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding NodeType}"></TextBlock>
|
||||
<TextBlock Text="{Binding AnotherName}" Margin="4,0,0,0"></TextBlock>
|
||||
<TextBlock Text="{Binding MethodName}" Margin="6,0,0,0"></TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
Background="#FACFC1"
|
||||
ItemTemplate="{StaticResource NodeListTemplate}">
|
||||
</ListBox>
|
||||
|
||||
<ListBox Grid.Row="3" Margin="6,2,2,2" ItemsSource="{Binding UINodes}"
|
||||
Visibility="{Binding UINodes, Converter={StaticResource CountToVisibilityConverter}}"
|
||||
Background="#FFFBD7">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="2" >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding NodeType}"></TextBlock>
|
||||
<TextBlock Text="{Binding AnotherName}" Margin="4,0,0,0"></TextBlock>
|
||||
<TextBlock Text="{Binding MethodName}" Margin="6,0,0,0"></TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
Background="#FFFBD7"
|
||||
ItemTemplate="{StaticResource NodeListTemplate}">
|
||||
</ListBox>-->
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
@@ -90,3 +72,9 @@
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
|
||||
<!--<custom:FlowMethodInfoListBox Grid.Row="1" Nodes="{Binding ActionNodes}" BackgroundColor="#D0F1F9"/>
|
||||
<custom:FlowMethodInfoListBox Grid.Row="2" Nodes="{Binding FlipflopNodes}" BackgroundColor="#FACFC1"/>
|
||||
<custom:FlowMethodInfoListBox Grid.Row="3" Nodes="{Binding UINodes}" BackgroundColor="#FFFBD7"/> -->
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Workbench.ViewModels;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -21,10 +22,32 @@ namespace Serein.Workbench.Views
|
||||
/// </summary>
|
||||
public partial class FlowLibrarysView : UserControl
|
||||
{
|
||||
private FlowLibrarysViewModel ViewModel => DataContext as FlowLibrarysViewModel ?? throw new ArgumentNullException();
|
||||
public FlowLibrarysView()
|
||||
{
|
||||
this.DataContext = App.GetService<Locator>().FlowLibrarysViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void FlowLibrarysView_Drop(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
{
|
||||
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (file.EndsWith(".dll"))
|
||||
{
|
||||
ViewModel.LoadFileLibrary(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FlowLibrarysView_DragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
e.Effects = DragDropEffects.Copy;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Views"
|
||||
mc:Ignorable="d"
|
||||
Loaded="Window_Loaded"
|
||||
Title="FlowWorkbenchView" Height="450" Width="800">
|
||||
Title="FlowWorkbenchView" Height="450" Width="800"
|
||||
Closing="Window_Closing">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
@@ -23,7 +24,7 @@
|
||||
<local:MainMenuBarView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5"/>
|
||||
|
||||
<!--左侧功能区-->
|
||||
<Grid Grid.Row="1" Grid.Column="0" >
|
||||
<Grid Grid.Row="1" Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
@@ -31,10 +32,13 @@
|
||||
<!--<RowDefinition Height="3*"></RowDefinition>-->
|
||||
</Grid.RowDefinitions>
|
||||
<local:BaseNodesView Grid.Row="0" Grid.ColumnSpan="1" Margin="0,0,0,15"/>
|
||||
<local:FlowLibrarysView Grid.Row="1" Grid.ColumnSpan="1" Margin="0,0,0,15"/>
|
||||
<local:FlowLibrarysView Grid.Row="1" Grid.ColumnSpan="1" Margin="0,0,0,15" />
|
||||
</Grid>
|
||||
|
||||
<!--功能区和编辑区的分割线-->
|
||||
<GridSplitter Grid.Row="1" Grid.Column="1" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="#CCD5F0" />
|
||||
<!--流程编辑区-->
|
||||
<local:FlowEditView Grid.Row="1" Grid.Column="2"/>
|
||||
<!--编辑区和视图区的分割线-->
|
||||
<GridSplitter Grid.Row="1" Grid.Column="3" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="#CCD5F0" />
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Serein.Workbench.Views
|
||||
/// </summary>
|
||||
public partial class FlowWorkbenchView : Window
|
||||
{
|
||||
private FlowWorkbenchViewModel ViewModel => ViewModel as FlowWorkbenchViewModel;
|
||||
public FlowWorkbenchView()
|
||||
{
|
||||
this.DataContext = App.GetService<Locator>().FlowWorkbenchViewModel;
|
||||
@@ -40,5 +41,12 @@ namespace Serein.Workbench.Views
|
||||
this.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
|
||||
this.Height = System.Windows.SystemParameters.PrimaryScreenHeight;*/
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
// 确保所有窗口关闭
|
||||
LogWindow.Instance.Close();
|
||||
System.Windows.Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,22 @@
|
||||
<MenuItem Header="加载本地项目" ></MenuItem>
|
||||
<MenuItem Header="加载远程项目"></MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="编辑">
|
||||
<MenuItem Header="增加画布"></MenuItem>
|
||||
<MenuItem Header="删除当前画布"></MenuItem>
|
||||
|
||||
<MenuItem Header="画布">
|
||||
<MenuItem Header="增加画布" Command="{Binding CreateFlowCanvasCommand}"></MenuItem>
|
||||
<MenuItem Header="删除当前画布" Command="{Binding RemoteFlowCanvasCommand}"></MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="调试">
|
||||
|
||||
<MenuItem Header="运行">
|
||||
<MenuItem Header="运行(仅当前画布)" Command="{Binding StartCurrentCanvasFlowCommand}"></MenuItem>
|
||||
<MenuItem Header="运行(从起始节点)"></MenuItem>
|
||||
<MenuItem Header="运行(从选定节点)" ></MenuItem>
|
||||
<MenuItem Header="运行" Command="{Binding StartFlowCommand}"></MenuItem>
|
||||
<MenuItem Header="结束流程" ></MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="视图">
|
||||
<MenuItem Header="输出窗口" ></MenuItem>
|
||||
<MenuItem Header="输出窗口" Command="{Binding OpenEnvOutWindowCommand}"></MenuItem>
|
||||
<MenuItem Header="重置画布"></MenuItem>
|
||||
<MenuItem Header="定位节点" ></MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
Reference in New Issue
Block a user