mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-03 22:01:27 +08:00
添加了节点树视图。
This commit is contained in:
@@ -319,7 +319,7 @@ namespace Serein.Library.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// IOC容器发生变化
|
/// IOC容器发生变化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void IOCMembersChangedHandler();
|
public delegate void IOCMembersChangedHandler(IOCMembersChangedEventArgs eventArgs);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -338,18 +338,39 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Completeuild,
|
Completeuild,
|
||||||
}
|
}
|
||||||
public IOCMembersChangedEventArgs(Type[] types, object[] dependencies, object[] unfinishedDependencies)
|
public IOCMembersChangedEventArgs(string key, object instance)
|
||||||
{
|
{
|
||||||
this.Types = types;
|
this.Key = key;
|
||||||
this.Dependencies = dependencies;
|
this.Instance = instance;
|
||||||
this.UnfinishedDependencies = unfinishedDependencies;
|
|
||||||
}
|
}
|
||||||
public Type[] Types { get; protected set; }
|
public string Key { get; private set; }
|
||||||
public object[] Dependencies { get; private set; }
|
public object Instance { get; private set; }
|
||||||
public object[] UnfinishedDependencies { get; private set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
//public class IOCMembersChangedEventArgs : FlowEventArgs
|
||||||
|
//{
|
||||||
|
// //public enum EventType
|
||||||
|
// //{
|
||||||
|
// // /// <summary>
|
||||||
|
// // /// 登记了类型
|
||||||
|
// // /// </summary>
|
||||||
|
// // Registered,
|
||||||
|
// // /// <summary>
|
||||||
|
// // /// 构建了类型
|
||||||
|
// // /// </summary>
|
||||||
|
// // Completeuild,
|
||||||
|
// //}
|
||||||
|
// public IOCMembersChangedEventArgs(Type[] types, object[] dependencies, object[] unfinishedDependencies)
|
||||||
|
// {
|
||||||
|
// this.Types = types;
|
||||||
|
// this.Dependencies = dependencies;
|
||||||
|
// this.UnfinishedDependencies = unfinishedDependencies;
|
||||||
|
// }
|
||||||
|
// public Type[] Types { get; protected set; }
|
||||||
|
// public object[] Dependencies { get; private set; }
|
||||||
|
// public object[] UnfinishedDependencies { get; private set; }
|
||||||
|
|
||||||
|
//}
|
||||||
public interface IFlowEnvironment
|
public interface IFlowEnvironment
|
||||||
{
|
{
|
||||||
#region 属性
|
#region 属性
|
||||||
@@ -420,9 +441,26 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
event ExpInterruptTriggerHandler OnInterruptTrigger;
|
event ExpInterruptTriggerHandler OnInterruptTrigger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IOC容器发生改变
|
||||||
|
/// </summary>
|
||||||
|
event IOCMembersChangedHandler OnIOCMembersChanged;
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取方法描述
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="md"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool TryGetMethodDetails(string methodName, out MethodDetails md);
|
||||||
|
|
||||||
|
|
||||||
|
//bool TryGetNodeData(string methodName, out NodeData node);
|
||||||
|
|
||||||
#region Workbench
|
#region Workbench
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -445,14 +483,7 @@ namespace Serein.Library.Api
|
|||||||
/// 清理加载的DLL(待更改)
|
/// 清理加载的DLL(待更改)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ClearAll();
|
void ClearAll();
|
||||||
/// <summary>
|
|
||||||
/// 获取方法描述
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="md"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool TryGetMethodDetails(string methodName, out MethodDetails md);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始运行
|
/// 开始运行
|
||||||
@@ -517,7 +548,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="nodeGuid"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <param name="expression"></param>
|
/// <param name="expression"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool AddInterruptExpression(object obj, string expression);
|
bool AddInterruptExpression(string key, string expression);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加作用于指定节点的中断表达式
|
/// 添加作用于指定节点的中断表达式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -538,7 +569,7 @@ namespace Serein.Library.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">需要监视的对象</param>
|
/// <param name="obj">需要监视的对象</param>
|
||||||
/// <param name="isMonitor">是否启用监视</param>
|
/// <param name="isMonitor">是否启用监视</param>
|
||||||
void SetMonitorObjState(object obj, bool isMonitor);
|
void SetMonitorObjState(string key,bool isMonitor);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查一个对象是否处于监听状态,如果是,则传出与该对象相关的表达式(用于中断),如果不是,则返回false。
|
/// 检查一个对象是否处于监听状态,如果是,则传出与该对象相关的表达式(用于中断),如果不是,则返回false。
|
||||||
@@ -546,7 +577,7 @@ namespace Serein.Library.Api
|
|||||||
/// <param name="obj">判断的对象</param>
|
/// <param name="obj">判断的对象</param>
|
||||||
/// <param name="exps">表达式</param>
|
/// <param name="exps">表达式</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool CheckObjMonitorState(object obj, out List<string> exps);
|
bool CheckObjMonitorState(string key, out List<string> exps);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Serein.Library.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否保护参数
|
/// 是否保护参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsProtectionParameter { get; set; } = true;
|
public bool IsProtectionParameter { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 作用实例的类型
|
/// 作用实例的类型
|
||||||
|
|||||||
10
Library/Entity/NodeData.cs
Normal file
10
Library/Entity/NodeData.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Serein.Library.Entity
|
||||||
|
{
|
||||||
|
public class NodeData
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,25 +7,26 @@ namespace Serein.Library.Enums
|
|||||||
public enum ConnectionType
|
public enum ConnectionType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 不执行分支
|
/// 默认属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
None,
|
None,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 真分支
|
/// 上游分支(执行当前节点前会执行一次上游分支),默认执行。
|
||||||
|
/// </summary>
|
||||||
|
Upstream,
|
||||||
|
/// <summary>
|
||||||
|
/// 真分支(表示当前节点顺利完成)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IsSucceed,
|
IsSucceed,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 假分支
|
/// 假分支(一般用于条件控件,条件为假时才会触发该类型的分支)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IsFail,
|
IsFail,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异常发生分支
|
/// 异常发生分支(当前节点对应的方法执行时出现非预期的异常)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IsError,
|
IsError,
|
||||||
/// <summary>
|
|
||||||
/// 上游分支(执行当前节点前会执行一次上游分支)
|
|
||||||
/// </summary>
|
|
||||||
Upstream,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace Serein.Library.Utils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentDictionary<string, List<(object,PropertyInfo)>> _unfinishedDependencies;
|
private readonly ConcurrentDictionary<string, List<(object,PropertyInfo)>> _unfinishedDependencies;
|
||||||
|
|
||||||
|
public event IOCMembersChangedHandler OnIOCMembersChanged;
|
||||||
|
|
||||||
public SereinIOC()
|
public SereinIOC()
|
||||||
{
|
{
|
||||||
@@ -112,7 +112,7 @@ namespace Serein.Library.Utils
|
|||||||
// 是接口类型,存在注册信息
|
// 是接口类型,存在注册信息
|
||||||
Register(type);// 注册类型信息
|
Register(type);// 注册类型信息
|
||||||
value = Instantiate(implementationType); // 创建实例对象,并注入依赖
|
value = Instantiate(implementationType); // 创建实例对象,并注入依赖
|
||||||
_dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中
|
CustomRegisterInstance(type.FullName, value);// 登记到IOC容器中
|
||||||
_typeMappings.TryRemove(type.FullName, out _); // 取消类型的注册信息
|
_typeMappings.TryRemove(type.FullName, out _); // 取消类型的注册信息
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -127,7 +127,7 @@ namespace Serein.Library.Utils
|
|||||||
// 不是接口,直接注册
|
// 不是接口,直接注册
|
||||||
Register(type);// 注册类型信息
|
Register(type);// 注册类型信息
|
||||||
value = Instantiate(type); // 创建实例对象,并注入依赖
|
value = Instantiate(type); // 创建实例对象,并注入依赖
|
||||||
_dependencies.TryAdd(type.FullName, value); // 登记到IOC容器中
|
CustomRegisterInstance(type.FullName, value);// 登记到IOC容器中
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
@@ -151,33 +151,26 @@ namespace Serein.Library.Utils
|
|||||||
|
|
||||||
#region 通过名称记录或获取一个实例
|
#region 通过名称记录或获取一个实例
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
public void CustomRegisterInstance(string name, object instance, bool needInjectProperty = true)
|
/// 指定key值注册一个已经实例化的实例对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <param name="needInjectProperty"></param>
|
||||||
|
public void CustomRegisterInstance(string key, object instance, bool needInjectProperty = true)
|
||||||
{
|
{
|
||||||
// 不存在时才允许创建
|
// 不存在时才允许创建
|
||||||
if (!_dependencies.ContainsKey(name))
|
if (!_dependencies.ContainsKey(key))
|
||||||
{
|
{
|
||||||
_dependencies.TryAdd(name, instance);
|
_dependencies.TryAdd(key, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needInjectProperty)
|
if (needInjectProperty)
|
||||||
{
|
{
|
||||||
InjectDependencies(instance); // 注入实例需要的依赖项
|
InjectDependencies(instance); // 注入实例需要的依赖项
|
||||||
}
|
}
|
||||||
|
InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型
|
||||||
// 检查是否存在其它实例
|
OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance));
|
||||||
if (_unfinishedDependencies.TryGetValue(name, out var unfinishedPropertyList))
|
|
||||||
{
|
|
||||||
foreach ((object obj, PropertyInfo property) in unfinishedPropertyList)
|
|
||||||
{
|
|
||||||
property.SetValue(obj, instance); //注入依赖项
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_unfinishedDependencies.TryRemove(name, out unfinishedPropertyList))
|
|
||||||
{
|
|
||||||
unfinishedPropertyList.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public object Get(Type type)
|
public object Get(Type type)
|
||||||
{
|
{
|
||||||
@@ -237,30 +230,20 @@ namespace Serein.Library.Utils
|
|||||||
// 遍历已注册类型
|
// 遍历已注册类型
|
||||||
foreach (var type in _typeMappings.Values.ToArray())
|
foreach (var type in _typeMappings.Values.ToArray())
|
||||||
{
|
{
|
||||||
|
if (!_dependencies.ContainsKey(type.FullName))
|
||||||
if (_dependencies.ContainsKey(type.FullName))
|
|
||||||
{
|
{
|
||||||
// 已经存在实例,不用管
|
var value = CreateInstance(type); // 绑定时注册的类型如果没有创建实例,则创建对应的实例
|
||||||
|
CustomRegisterInstance(type.FullName, value);// 登记到IOC容器中
|
||||||
}
|
}
|
||||||
else
|
_typeMappings.TryRemove(type.FullName, out _); // 移除类型的注册记录
|
||||||
{
|
|
||||||
// 如果没有创建实例,则创建对应的实例
|
|
||||||
_dependencies[type.FullName] = CreateInstance(type);
|
|
||||||
}
|
|
||||||
// 移除类型的注册记录
|
|
||||||
_typeMappings.TryRemove(type.FullName, out _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注入实例的依赖项
|
|
||||||
foreach (var instance in _dependencies.Values)
|
foreach (var instance in _dependencies.Values)
|
||||||
{
|
{
|
||||||
InjectDependencies(instance);
|
InjectDependencies(instance); // 绑定时注入实例的依赖项
|
||||||
}
|
}
|
||||||
|
|
||||||
//var instance = Instantiate(item.Value);
|
|
||||||
|
|
||||||
// TryInstantiateWaitingDependencies();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -292,19 +275,24 @@ namespace Serein.Library.Utils
|
|||||||
private object CreateInstance(Type type, params object[] parameters)
|
private object CreateInstance(Type type, params object[] parameters)
|
||||||
{
|
{
|
||||||
var instance = Activator.CreateInstance(type);
|
var instance = Activator.CreateInstance(type);
|
||||||
if (_unfinishedDependencies.TryGetValue(type.FullName, out var unfinishedPropertyList))
|
InjectUnfinishedDependencies(type.FullName, instance);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InjectUnfinishedDependencies(string key,object instance)
|
||||||
|
{
|
||||||
|
if (_unfinishedDependencies.TryGetValue(key, out var unfinishedPropertyList))
|
||||||
{
|
{
|
||||||
foreach ((object obj, PropertyInfo property) in unfinishedPropertyList)
|
foreach ((object obj, PropertyInfo property) in unfinishedPropertyList)
|
||||||
{
|
{
|
||||||
property.SetValue(obj, instance); //注入依赖项
|
property.SetValue(obj, instance); //注入依赖项
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_unfinishedDependencies.TryRemove(type.FullName, out unfinishedPropertyList))
|
if (_unfinishedDependencies.TryRemove(key, out unfinishedPropertyList))
|
||||||
{
|
{
|
||||||
unfinishedPropertyList.Clear();
|
unfinishedPropertyList.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,14 @@ namespace Serein.NodeFlow.Base
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
|
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract partial class NodeModelBase :IDynamicFlowNode
|
public abstract partial class NodeModelBase : IDynamicFlowNode
|
||||||
{
|
{
|
||||||
private static readonly ConnectionType[] ct = [ConnectionType.IsSucceed,
|
|
||||||
ConnectionType.IsFail,
|
|
||||||
ConnectionType.IsError,
|
|
||||||
ConnectionType.Upstream];
|
|
||||||
public NodeModelBase()
|
public NodeModelBase()
|
||||||
{
|
{
|
||||||
PreviousNodes = [];
|
PreviousNodes = [];
|
||||||
SuccessorNodes = [];
|
SuccessorNodes = [];
|
||||||
foreach (ConnectionType ctType in ct)
|
foreach (ConnectionType ctType in NodeStaticConfig.ConnectionTypes)
|
||||||
{
|
{
|
||||||
PreviousNodes[ctType] = [];
|
PreviousNodes[ctType] = [];
|
||||||
SuccessorNodes[ctType] = [];
|
SuccessorNodes[ctType] = [];
|
||||||
@@ -71,6 +68,9 @@ namespace Serein.NodeFlow.Base
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<ConnectionType,List<NodeModelBase>> SuccessorNodes { get; }
|
public Dictionary<ConnectionType,List<NodeModelBase>> SuccessorNodes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前节点执行完毕后需要执行的下一个分支的类别
|
||||||
|
/// </summary>
|
||||||
public ConnectionType NextOrientation { get; set; } = ConnectionType.None;
|
public ConnectionType NextOrientation { get; set; } = ConnectionType.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -426,10 +426,10 @@ namespace Serein.NodeFlow.Base
|
|||||||
private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object data, int type)
|
private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object data, int type)
|
||||||
{
|
{
|
||||||
MonitorObjectEventArgs.ObjSourceType sourceType;
|
MonitorObjectEventArgs.ObjSourceType sourceType;
|
||||||
object key;
|
string key;
|
||||||
if(type == 0)
|
if(type == 0)
|
||||||
{
|
{
|
||||||
key = data;
|
key = data.GetType().FullName;
|
||||||
sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj;
|
sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -450,6 +450,7 @@ namespace Serein.NodeFlow.Base
|
|||||||
for (int i = 0; i < exps.Count && !isExpInterrupt; i++)
|
for (int i = 0; i < exps.Count && !isExpInterrupt; i++)
|
||||||
{
|
{
|
||||||
exp = exps[i];
|
exp = exps[i];
|
||||||
|
if (string.IsNullOrEmpty(exp)) continue;
|
||||||
isExpInterrupt = SereinConditionParser.To(data, exp);
|
isExpInterrupt = SereinConditionParser.To(data, exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,7 +459,7 @@ namespace Serein.NodeFlow.Base
|
|||||||
InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
|
InterruptClass interruptClass = InterruptClass.Branch; // 分支中断
|
||||||
if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass))
|
if (context.Env.SetNodeInterrupt(nodeModel.Guid, interruptClass))
|
||||||
{
|
{
|
||||||
context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Obj);
|
context.Env.TriggerInterrupt(nodeModel.Guid, exp, InterruptTriggerEventArgs.InterruptTriggerType.Exp);
|
||||||
var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
|
var cancelType = await nodeModel.DebugSetting.GetInterruptTask();
|
||||||
await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支");
|
await Console.Out.WriteLineAsync($"[{data}]中断已{cancelType},开始执行后继分支");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,8 +55,12 @@ namespace Serein.NodeFlow
|
|||||||
FlipflopNodes = new List<SingleFlipflopNode>();
|
FlipflopNodes = new List<SingleFlipflopNode>();
|
||||||
IsGlobalInterrupt = false;
|
IsGlobalInterrupt = false;
|
||||||
flowStarter = null;
|
flowStarter = null;
|
||||||
|
|
||||||
|
sereinIOC.OnIOCMembersChanged += e => this?.OnIOCMembersChanged?.Invoke(e) ; // 监听IOC容器的注册
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点的命名空间
|
/// 节点的命名空间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -113,6 +117,11 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event ExpInterruptTriggerHandler OnInterruptTrigger;
|
public event ExpInterruptTriggerHandler OnInterruptTrigger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 容器改变
|
||||||
|
/// </summary>
|
||||||
|
public event IOCMembersChangedHandler OnIOCMembersChanged;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 属性
|
#region 属性
|
||||||
@@ -133,13 +142,14 @@ namespace Serein.NodeFlow
|
|||||||
public ChannelFlowInterrupt ChannelFlowInterrupt { get; set; }
|
public ChannelFlowInterrupt ChannelFlowInterrupt { get; set; }
|
||||||
|
|
||||||
public ISereinIOC IOC { get => this; }
|
public ISereinIOC IOC { get => this; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 私有变量
|
#region 私有变量
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 容器管理
|
/// 容器管理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private SereinIOC sereinIOC;
|
private readonly SereinIOC sereinIOC;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储加载的程序集路径
|
/// 存储加载的程序集路径
|
||||||
@@ -666,9 +676,9 @@ namespace Serein.NodeFlow
|
|||||||
/// <param name="nodeGuid"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <param name="expression"></param>
|
/// <param name="expression"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool AddInterruptExpression(object obj, string expression)
|
public bool AddInterruptExpression(string key, string expression)
|
||||||
{
|
{
|
||||||
if (dictMonitorObjExpInterrupt.TryGetValue(obj, out var condition))
|
if (dictMonitorObjExpInterrupt.TryGetValue(key, out var condition))
|
||||||
{
|
{
|
||||||
condition.Clear(); // 暂时
|
condition.Clear(); // 暂时
|
||||||
condition.Add(expression);// 暂时
|
condition.Add(expression);// 暂时
|
||||||
@@ -678,7 +688,7 @@ namespace Serein.NodeFlow
|
|||||||
{
|
{
|
||||||
var exps = new List<string>();
|
var exps = new List<string>();
|
||||||
exps.Add(expression);
|
exps.Add(expression);
|
||||||
dictMonitorObjExpInterrupt.TryAdd(obj, exps);
|
dictMonitorObjExpInterrupt.TryAdd(key, exps);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -735,7 +745,7 @@ namespace Serein.NodeFlow
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 要监视的对象,以及与其关联的表达式
|
/// 要监视的对象,以及与其关联的表达式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ConcurrentDictionary<object, List<string>> dictMonitorObjExpInterrupt = [];
|
private ConcurrentDictionary<string, List<string>> dictMonitorObjExpInterrupt = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置对象的监视状态
|
/// 设置对象的监视状态
|
||||||
@@ -743,22 +753,22 @@ namespace Serein.NodeFlow
|
|||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <param name="isMonitor"></param>
|
/// <param name="isMonitor"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public void SetMonitorObjState(object obj, bool isMonitor)
|
public void SetMonitorObjState(string key, bool isMonitor)
|
||||||
{
|
{
|
||||||
if (obj is null) { return; }
|
if (string.IsNullOrEmpty(key)) { return; }
|
||||||
var isExist = dictMonitorObjExpInterrupt.ContainsKey(obj);
|
var isExist = dictMonitorObjExpInterrupt.ContainsKey(key);
|
||||||
if (isExist)
|
if (isExist)
|
||||||
{
|
{
|
||||||
if (!isMonitor) // 对象存在且需要不监视
|
if (!isMonitor) // 对象存在且需要不监视
|
||||||
{
|
{
|
||||||
dictMonitorObjExpInterrupt.Remove(obj, out _);
|
dictMonitorObjExpInterrupt.Remove(key, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isMonitor) // 对象不存在且需要监视,添加在集合中。
|
if (isMonitor) // 对象不存在且需要监视,添加在集合中。
|
||||||
{
|
{
|
||||||
dictMonitorObjExpInterrupt.TryAdd(obj, new List<string>()); ;
|
dictMonitorObjExpInterrupt.TryAdd(key, new List<string>()); ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -769,10 +779,10 @@ namespace Serein.NodeFlow
|
|||||||
/// <param name="nodeGuid"></param>
|
/// <param name="nodeGuid"></param>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool CheckObjMonitorState(object obj, out List<string>? exps)
|
public bool CheckObjMonitorState(string key, out List<string>? exps)
|
||||||
{
|
{
|
||||||
if (obj is null) { exps = null; return false; }
|
if (string.IsNullOrEmpty(key)) { exps = null; return false; }
|
||||||
return dictMonitorObjExpInterrupt.TryGetValue(obj, out exps);
|
return dictMonitorObjExpInterrupt.TryGetValue(key, out exps);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Serein.Library.Api;
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Enums;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -14,6 +15,10 @@ namespace Serein.NodeFlow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string NodeSpaceName = $"{nameof(Serein)}.{nameof(Serein.NodeFlow)}.{nameof(Serein.NodeFlow.Model)}";
|
public const string NodeSpaceName = $"{nameof(Serein)}.{nameof(Serein.NodeFlow)}.{nameof(Serein.NodeFlow.Model)}";
|
||||||
|
|
||||||
|
public static readonly ConnectionType[] ConnectionTypes = [
|
||||||
|
ConnectionType.Upstream,
|
||||||
|
ConnectionType.IsSucceed,
|
||||||
|
ConnectionType.IsFail,
|
||||||
|
ConnectionType.IsError];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
<Button x:Name="ButtonDebugRun" Content="运行" Width="100" Margin="10" Click="ButtonDebugRun_Click"></Button>
|
<Button x:Name="ButtonDebugRun" Content="运行" Width="100" Margin="10" Click="ButtonDebugRun_Click"></Button>
|
||||||
<Button x:Name="ButtonDebugFlipflopNode" Content="结束" Width="100" Margin="10" Click="ButtonDebugFlipflopNode_Click"></Button>
|
<Button x:Name="ButtonDebugFlipflopNode" Content="结束" Width="100" Margin="10" Click="ButtonDebugFlipflopNode_Click"></Button>
|
||||||
<Button x:Name="ButtonStartFlowInSelectNode" Content="从选定节点开始" Width="100" Margin="10" Click="ButtonStartFlowInSelectNode_Click"></Button>
|
<Button x:Name="ButtonStartFlowInSelectNode" Content="从选定节点开始" Width="100" Margin="10" Click="ButtonStartFlowInSelectNode_Click"></Button>
|
||||||
|
<!--<Button x:Name="ButtonLoadStartNodeTree" Content="加载起始节点树" Width="100" Margin="10" Click="ButtonLoadStartNodeTree_Click"></Button>-->
|
||||||
<!--<Button x:Name="ButtonReflushCanvasConfig" Content="重置画布设置" Width="100" Margin="10" Click="ButtonReflushCanvasConfig_Click"></Button>-->
|
<!--<Button x:Name="ButtonReflushCanvasConfig" Content="重置画布设置" Width="100" Margin="10" Click="ButtonReflushCanvasConfig_Click"></Button>-->
|
||||||
<!--<Button x:Name="ButtonLoadCanvasConfig" Content="加载画布设置" Width="100" Margin="10" Click="ButtonLoadCanvasConfig_Click"></Button>-->
|
<!--<Button x:Name="ButtonLoadCanvasConfig" Content="加载画布设置" Width="100" Margin="10" Click="ButtonLoadCanvasConfig_Click"></Button>-->
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -190,12 +191,13 @@ Canvas.Top="{Binding ActualHeight, ElementName=FlowChartCanvas, Mode=OneWay, Con
|
|||||||
<!--IOC容器属性-->
|
<!--IOC容器属性-->
|
||||||
<Grid Grid.Column="4" >
|
<Grid Grid.Column="4" >
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Grid.Row="0" >
|
<Grid Grid.Row="0" >
|
||||||
<!--<themes:LazyTreeView x:Name="lazyTreeView" />-->
|
<!--<themes:LazyTreeView x:Name="lazyTreeView" />-->
|
||||||
|
<themes:NodeTreeViewControl x:Name="NodeTreeViewer"></themes:NodeTreeViewControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Grid.Row="1" >
|
<Grid Grid.Row="1" >
|
||||||
<themes:IOCObjectViewControl x:Name="IOCObjectViewer">
|
<themes:IOCObjectViewControl x:Name="IOCObjectViewer">
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ namespace Serein.WorkBench
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private List<Connection> Connections { get; } = [];
|
private List<Connection> Connections { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 起始节点
|
||||||
|
/// </summary>
|
||||||
|
//private NodeControlBase StartNodeControl{ get; set; }
|
||||||
|
|
||||||
#region 与画布相关的字段
|
#region 与画布相关的字段
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -149,6 +154,7 @@ namespace Serein.WorkBench
|
|||||||
ViewModel = new MainWindowViewModel(this);
|
ViewModel = new MainWindowViewModel(this);
|
||||||
FlowEnvironment = ViewModel.FlowEnvironment;
|
FlowEnvironment = ViewModel.FlowEnvironment;
|
||||||
ViewObjectViewer.FlowEnvironment = FlowEnvironment;
|
ViewObjectViewer.FlowEnvironment = FlowEnvironment;
|
||||||
|
IOCObjectViewer.FlowEnvironment = FlowEnvironment;
|
||||||
|
|
||||||
InitFlowEnvironmentEvent(); // 配置环境事件
|
InitFlowEnvironmentEvent(); // 配置环境事件
|
||||||
logWindow = InitConsoleOut(); // 重定向 Console 输出
|
logWindow = InitConsoleOut(); // 重定向 Console 输出
|
||||||
@@ -160,6 +166,9 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
FlowEnvironment.LoadProject(App.FlowProjectData, App.FileDataPath); // 加载项目
|
FlowEnvironment.LoadProject(App.FlowProjectData, App.FileDataPath); // 加载项目
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IOCObjectViewer.SelectObj += ViewObjectViewer.LoadObjectInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitFlowEnvironmentEvent()
|
private void InitFlowEnvironmentEvent()
|
||||||
@@ -178,6 +187,8 @@ namespace Serein.WorkBench
|
|||||||
FlowEnvironment.OnNodeInterruptStateChange += FlowEnvironment_OnNodeInterruptStateChange;
|
FlowEnvironment.OnNodeInterruptStateChange += FlowEnvironment_OnNodeInterruptStateChange;
|
||||||
FlowEnvironment.OnInterruptTrigger += FlowEnvironment_OnInterruptTrigger;
|
FlowEnvironment.OnInterruptTrigger += FlowEnvironment_OnInterruptTrigger;
|
||||||
|
|
||||||
|
FlowEnvironment.OnIOCMembersChanged += FlowEnvironment_OnIOCMembersChanged;
|
||||||
|
|
||||||
}
|
}
|
||||||
private void InitCanvasUI()
|
private void InitCanvasUI()
|
||||||
{
|
{
|
||||||
@@ -242,8 +253,6 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 运行环境事件
|
#region 运行环境事件
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载完成
|
/// 加载完成
|
||||||
@@ -265,7 +274,8 @@ namespace Serein.WorkBench
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
private void FlowEnvironment_OnFlowRunComplete(FlowEventArgs eventArgs)
|
private void FlowEnvironment_OnFlowRunComplete(FlowEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
Console.WriteLine("-------运行完成---------\r\n");
|
Console.WriteLine("-------运行完成---------\r\n");
|
||||||
|
IOCObjectViewer.ClearObjItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -307,48 +317,69 @@ namespace Serein.WorkBench
|
|||||||
/// <param name="connectionType"></param>
|
/// <param name="connectionType"></param>
|
||||||
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
private void FlowEnvironment_NodeConnectChangeEvemt(NodeConnectChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
this.Dispatcher.Invoke(() =>
|
string fromNodeGuid = eventArgs.FromNodeGuid;
|
||||||
|
string toNodeGuid = eventArgs.ToNodeGuid;
|
||||||
|
NodeControlBase fromNode = GuidToControl(fromNodeGuid);
|
||||||
|
NodeControlBase toNode = GuidToControl(toNodeGuid);
|
||||||
|
|
||||||
|
ConnectionType connectionType = eventArgs.ConnectionType;
|
||||||
|
Action? action = null;
|
||||||
|
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create) // 添加连接
|
||||||
{
|
{
|
||||||
string fromNodeGuid = eventArgs.FromNodeGuid;
|
// 添加连接
|
||||||
string toNodeGuid = eventArgs.ToNodeGuid;
|
var connection = new Connection
|
||||||
NodeControlBase fromNode = GuidToControl(fromNodeGuid);
|
|
||||||
NodeControlBase toNode = GuidToControl(toNodeGuid);
|
|
||||||
ConnectionType connectionType = eventArgs.ConnectionType;
|
|
||||||
if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Create)
|
|
||||||
{
|
{
|
||||||
lock (Connections)
|
Start = fromNode,
|
||||||
{
|
End = toNode,
|
||||||
// 添加连接
|
Type = connectionType
|
||||||
var connection = new Connection
|
};
|
||||||
{
|
if (toNode is FlipflopNodeControl flipflopControl) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
|
||||||
Start = fromNode,
|
{
|
||||||
End = toNode,
|
var nodeModel = flipflopControl?.ViewModel?.Node;
|
||||||
Type = connectionType
|
NodeTreeViewer.RemoteGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
||||||
};
|
|
||||||
|
|
||||||
BsControl.Draw(FlowChartCanvas, connection); // 添加贝塞尔曲线显示
|
|
||||||
ConfigureLineContextMenu(connection); // 设置连接右键事件
|
|
||||||
Connections.Add(connection);
|
|
||||||
EndConnection();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote)
|
|
||||||
|
action = () => {
|
||||||
|
BsControl.Draw(FlowChartCanvas, connection); // 添加贝塞尔曲线显示
|
||||||
|
ConfigureLineContextMenu(connection); // 设置连接右键事件
|
||||||
|
Connections.Add(connection);
|
||||||
|
EndConnection();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (eventArgs.ChangeType == NodeConnectChangeEventArgs.ConnectChangeType.Remote) // 移除连接
|
||||||
|
{
|
||||||
|
// 需要移除连接
|
||||||
|
var removeConnections = Connections.Where(c => c.Start.ViewModel.Node.Guid.Equals(fromNodeGuid)
|
||||||
|
&& c.End.ViewModel.Node.Guid.Equals(toNodeGuid))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
|
action = () =>
|
||||||
{
|
{
|
||||||
// 需要移除连接
|
|
||||||
var removeConnections = Connections.Where(c => c.Start.ViewModel.Node.Guid.Equals(fromNodeGuid)
|
|
||||||
&& c.End.ViewModel.Node.Guid.Equals(toNodeGuid))
|
|
||||||
.ToList();
|
|
||||||
foreach (var connection in removeConnections)
|
foreach (var connection in removeConnections)
|
||||||
{
|
{
|
||||||
connection.RemoveFromCanvas();
|
connection.RemoveFromCanvas();
|
||||||
Connections.Remove(connection);
|
Connections.Remove(connection);
|
||||||
|
JudgmentFlipFlopNode(connection.End); // 连接关系变更时判断
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
action?.Invoke();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点移除事件
|
/// 节点移除事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -364,9 +395,19 @@ namespace Serein.WorkBench
|
|||||||
selectNodeControls.Remove(nodeControl);
|
selectNodeControls.Remove(nodeControl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#region 节点树视图
|
||||||
|
if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器
|
||||||
|
{
|
||||||
|
var node = flipflopControl?.ViewModel?.Node;
|
||||||
|
if (node is not null)
|
||||||
|
{
|
||||||
|
NodeTreeViewer.RemoteGlobalFlipFlop(node); // 从全局触发器树树视图中移除
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
this.Dispatcher.Invoke(() =>
|
this.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
|
||||||
FlowChartCanvas.Children.Remove(nodeControl);
|
FlowChartCanvas.Children.Remove(nodeControl);
|
||||||
NodeControls.Remove(nodeControl.ViewModel.Node.Guid);
|
NodeControls.Remove(nodeControl.ViewModel.Node.Guid);
|
||||||
});
|
});
|
||||||
@@ -404,7 +445,6 @@ namespace Serein.WorkBench
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NodeControls.TryAdd(nodeModelBase.Guid, nodeControl);
|
NodeControls.TryAdd(nodeModelBase.Guid, nodeControl);
|
||||||
|
|
||||||
if (eventArgs.IsAddInRegion && NodeControls.TryGetValue(eventArgs.RegeionGuid, out NodeControlBase? regionControl))
|
if (eventArgs.IsAddInRegion && NodeControls.TryGetValue(eventArgs.RegeionGuid, out NodeControlBase? regionControl))
|
||||||
{
|
{
|
||||||
if (regionControl is not null)
|
if (regionControl is not null)
|
||||||
@@ -415,13 +455,23 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!TryPlaceNodeInRegion(nodeControl, position))
|
if (!TryPlaceNodeInRegion(nodeControl, position)) // 将节点放置在区域中
|
||||||
{
|
{
|
||||||
PlaceNodeOnCanvas(nodeControl, position.X, position.Y);
|
PlaceNodeOnCanvas(nodeControl, position.X, position.Y); // 将节点放置在画布上
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region 节点树视图
|
||||||
|
if (nodeModelBase.ControlType == NodeControlType.Flipflop)
|
||||||
|
{
|
||||||
|
var node = nodeControl?.ViewModel?.Node;
|
||||||
|
if(node is not null)
|
||||||
|
{
|
||||||
|
NodeTreeViewer.AddGlobalFlipFlop(FlowEnvironment, node); // 新增的触发器节点添加到全局触发器
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -450,6 +500,11 @@ namespace Serein.WorkBench
|
|||||||
|
|
||||||
newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
newStartNodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
||||||
newStartNodeControl.BorderThickness = new Thickness(2);
|
newStartNodeControl.BorderThickness = new Thickness(2);
|
||||||
|
var node = newStartNodeControl?.ViewModel?.Node;
|
||||||
|
if (node is not null)
|
||||||
|
{
|
||||||
|
NodeTreeViewer.LoadNodeTreeOfStartNode(FlowEnvironment, node);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -463,10 +518,10 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
string nodeGuid = eventArgs.NodeGuid;
|
string nodeGuid = eventArgs.NodeGuid;
|
||||||
|
|
||||||
object monitorKey = MonitorObjectEventArgs.ObjSourceType.NodeFlowData switch
|
string monitorKey = MonitorObjectEventArgs.ObjSourceType.NodeFlowData switch
|
||||||
{
|
{
|
||||||
MonitorObjectEventArgs.ObjSourceType.NodeFlowData => nodeGuid,
|
MonitorObjectEventArgs.ObjSourceType.NodeFlowData => nodeGuid,
|
||||||
_ => eventArgs.NewData,
|
_ => eventArgs.NewData.GetType().FullName,
|
||||||
};
|
};
|
||||||
|
|
||||||
//NodeControlBase nodeControl = GuidToControl(nodeGuid);
|
//NodeControlBase nodeControl = GuidToControl(nodeGuid);
|
||||||
@@ -548,6 +603,15 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IOC变更
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
private void FlowEnvironment_OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
IOCObjectViewer.AddDependenciesInstance(eventArgs.Key, eventArgs.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Guid 转 NodeControl
|
/// Guid 转 NodeControl
|
||||||
@@ -569,7 +633,6 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region 加载项目文件后触发事件相关方法
|
#region 加载项目文件后触发事件相关方法
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1081,46 +1144,9 @@ namespace Serein.WorkBench
|
|||||||
((UIElement)sender).CaptureMouse(); // 捕获鼠标
|
((UIElement)sender).CaptureMouse(); // 捕获鼠标
|
||||||
e.Handled = true; // 防止事件传播影响其他控件
|
e.Handled = true; // 防止事件传播影响其他控件
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeViewerObjOfNode(NodeControlBase nodeControl)
|
|
||||||
{
|
|
||||||
// int i = false;
|
|
||||||
var node = nodeControl?.ViewModel?.Node;
|
|
||||||
if (node is not null && node.MethodDetails.ReturnType != typeof(void))
|
|
||||||
{
|
|
||||||
if (ViewObjectViewer.MonitorObj is null)
|
|
||||||
{
|
|
||||||
FlowEnvironment.SetMonitorObjState(node.Guid, true); // 通知环境,该节点的数据更新后需要传到UI
|
|
||||||
// FlowEnvironment.SetMonitorObjState(nodeObj, true); // 通知环境,该节点的数据更新后需要传到UI
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var nodeObj = node.GetFlowData();
|
|
||||||
if (nodeObj is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//if (nodeObj.Equals(ViewObjectViewer.MonitorObj) == true)
|
|
||||||
//{
|
|
||||||
// // 选择同一个控件,不再监视
|
|
||||||
// ViewObjectViewer.RefreshObjectTree(nodeObj);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
if (node.Guid.Equals(ViewObjectViewer.MonitorKey) == true)
|
|
||||||
{
|
|
||||||
ViewObjectViewer.RefreshObjectTree(nodeObj);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FlowEnvironment.SetMonitorObjState(ViewObjectViewer.MonitorKey, false); // 取消对旧节点的监视
|
|
||||||
FlowEnvironment.SetMonitorObjState(node.Guid, true); // 通知环境,该节点的数据更新后需要传到UI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控件的鼠标移动事件,根据鼠标拖动更新控件的位置。批量移动计算移动逻辑。
|
/// 控件的鼠标移动事件,根据鼠标拖动更新控件的位置。批量移动计算移动逻辑。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1217,6 +1243,41 @@ namespace Serein.WorkBench
|
|||||||
startControlDragPoint = currentPosition; // 更新起始点位置
|
startControlDragPoint = currentPosition; // 更新起始点位置
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void ChangeViewerObjOfNode(NodeControlBase nodeControl)
|
||||||
|
{
|
||||||
|
|
||||||
|
var node = nodeControl?.ViewModel?.Node;
|
||||||
|
if (node is not null && node.MethodDetails.ReturnType != typeof(void))
|
||||||
|
{
|
||||||
|
var key = node.Guid;
|
||||||
|
var instance = node.GetFlowData();
|
||||||
|
ViewObjectViewer.LoadObjectInformation(key, instance);
|
||||||
|
ChangeViewerObj(key, instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void ChangeViewerObj(string key, object instance)
|
||||||
|
{
|
||||||
|
if (ViewObjectViewer.MonitorObj is null)
|
||||||
|
{
|
||||||
|
FlowEnvironment.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (instance is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key.Equals(ViewObjectViewer.MonitorKey) == true)
|
||||||
|
{
|
||||||
|
ViewObjectViewer.RefreshObjectTree(instance);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlowEnvironment.SetMonitorObjState(ViewObjectViewer.MonitorKey,false); // 取消对旧节点的监视
|
||||||
|
FlowEnvironment.SetMonitorObjState(key, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#region UI连接控件操作
|
#region UI连接控件操作
|
||||||
|
|
||||||
@@ -1229,6 +1290,7 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
IsControlDragging = false;
|
IsControlDragging = false;
|
||||||
((UIElement)sender).ReleaseMouseCapture(); // 释放鼠标捕获
|
((UIElement)sender).ReleaseMouseCapture(); // 释放鼠标捕获
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConnecting)
|
if (IsConnecting)
|
||||||
@@ -1240,6 +1302,7 @@ namespace Serein.WorkBench
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FlowEnvironment.ConnectNode(formNodeGuid, toNodeGuid, currentConnectionType);
|
FlowEnvironment.ConnectNode(formNodeGuid, toNodeGuid, currentConnectionType);
|
||||||
|
|
||||||
}
|
}
|
||||||
/*else if (IsConnecting)
|
/*else if (IsConnecting)
|
||||||
{
|
{
|
||||||
@@ -2156,7 +2219,28 @@ namespace Serein.WorkBench
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IOC视图管理
|
#region 节点数、IOC视图管理
|
||||||
|
|
||||||
|
private void JudgmentFlipFlopNode(NodeControlBase nodeControl)
|
||||||
|
{
|
||||||
|
if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器
|
||||||
|
{
|
||||||
|
var nodeModel = flipflopControl?.ViewModel?.Node;
|
||||||
|
int count = 0;
|
||||||
|
foreach (var ct in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
count += nodeModel.PreviousNodes[ct].Count;
|
||||||
|
}
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
NodeTreeViewer.AddGlobalFlipFlop(FlowEnvironment, nodeModel); // 添加到全局触发器树树视图
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NodeTreeViewer.RemoteGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void LoadIOCObjectViewer()
|
void LoadIOCObjectViewer()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -2366,7 +2450,6 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
|
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ namespace Serein.WorkBench.Node.ViewModel
|
|||||||
internal NodeModelBase Node { get; }
|
internal NodeModelBase Node { get; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private bool isSelect;
|
private bool isSelect;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 表示节点控件是否被选中
|
/// 表示节点控件是否被选中
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
<Page Remove="Node\FlipflopRegionControl.xaml" />
|
<Page Remove="Node\FlipflopRegionControl.xaml" />
|
||||||
<Page Remove="Themes\ConditionControl.xaml" />
|
<Page Remove="Themes\ConditionControl.xaml" />
|
||||||
<Page Remove="Themes\ExplicitDataControl.xaml" />
|
<Page Remove="Themes\ExplicitDataControl.xaml" />
|
||||||
|
<Page Remove="Themes\MultiConditionConverter.xaml" />
|
||||||
<Page Remove="Themes\ObjectViewerControl1.xaml" />
|
<Page Remove="Themes\ObjectViewerControl1.xaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -9,15 +9,18 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<!--<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>-->
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<GroupBox Grid.Row="0" Header="已注册待绑定的类型" Margin="5">
|
<GroupBox Grid.Row="1" Header="实例视图" Margin="5">
|
||||||
<ListBox x:Name="TypeListBox" Background="#E3F6FA"/>
|
|
||||||
</GroupBox>
|
|
||||||
<GroupBox Grid.Row="1" Header="完成注入的实例" Margin="5">
|
|
||||||
<ListBox x:Name="DependenciesListBox" Background="#E3FAE9"/>
|
<ListBox x:Name="DependenciesListBox" Background="#E3FAE9"/>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
<!--<GroupBox Grid.Row="0" Header="正在注册的类型" Margin="5">
|
||||||
|
<ListBox x:Name="TypeListBox" Background="#E3F6FA"/>
|
||||||
|
</GroupBox>-->
|
||||||
|
<!--<GroupBox Grid.Row="1" Header="实例视图" Margin="5">
|
||||||
|
<ListBox x:Name="DependenciesListBox" Background="#E3FAE9"/>
|
||||||
|
</GroupBox>-->
|
||||||
<!--<GroupBox Grid.Row="3" Header="未完成注入的实例" Margin="5">
|
<!--<GroupBox Grid.Row="3" Header="未完成注入的实例" Margin="5">
|
||||||
<ListBox x:Name="UnfinishedDependenciesListBox" Background="#FFE9D7"/>
|
<ListBox x:Name="UnfinishedDependenciesListBox" Background="#FFE9D7"/>
|
||||||
</GroupBox>-->
|
</GroupBox>-->
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Controls.Primitives;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
@@ -14,6 +15,7 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.WorkBench.Themes
|
namespace Serein.WorkBench.Themes
|
||||||
{
|
{
|
||||||
@@ -22,18 +24,96 @@ namespace Serein.WorkBench.Themes
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class IOCObjectViewControl : UserControl
|
public partial class IOCObjectViewControl : UserControl
|
||||||
{
|
{
|
||||||
private IOCObjectViewMoel IOCObjectViewMoel;
|
public Action<string,object> SelectObj { get; set; }
|
||||||
private SereinIOC sereinIOC;
|
|
||||||
public void SetIOC(SereinIOC sereinIOC)
|
|
||||||
{
|
|
||||||
this.sereinIOC = sereinIOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IOCObjectViewControl()
|
public IOCObjectViewControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
IOCObjectViewMoel = new IOCObjectViewMoel();
|
}
|
||||||
DataContext = IOCObjectViewMoel;
|
|
||||||
|
private class IOCObj
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
public object Instance { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 运行环境
|
||||||
|
/// </summary>
|
||||||
|
public IFlowEnvironment FlowEnvironment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加一个实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
public void AddDependenciesInstance(string key,object instance)
|
||||||
|
{
|
||||||
|
IOCObj iOCObj = new IOCObj
|
||||||
|
{
|
||||||
|
Key = key,
|
||||||
|
Instance = instance,
|
||||||
|
};
|
||||||
|
TextBlock textBlock = new TextBlock();
|
||||||
|
textBlock.Text = key;
|
||||||
|
textBlock.Tag = iOCObj;
|
||||||
|
textBlock.MouseDown += (s, e) =>
|
||||||
|
{
|
||||||
|
if(s is TextBlock block && block.Tag is IOCObj iocObj)
|
||||||
|
{
|
||||||
|
SelectObj?.Invoke(iocObj.Key, iocObj.Instance);
|
||||||
|
//FlowEnvironment.SetMonitorObjState(iocObj.Instance, true); // 通知环境,该节点的数据更新后需要传到UI
|
||||||
|
}
|
||||||
|
};
|
||||||
|
DependenciesListBox.Items.Add(textBlock);
|
||||||
|
SortLisbox(DependenciesListBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新一个实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
public void RefreshDependenciesInstance(string key, object instance)
|
||||||
|
{
|
||||||
|
foreach (var item in DependenciesListBox.Items)
|
||||||
|
{
|
||||||
|
if (item is TextBlock block && block.Tag is IOCObj iocObj && iocObj.Key.Equals(key))
|
||||||
|
{
|
||||||
|
iocObj.Instance = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearObjItem()
|
||||||
|
{
|
||||||
|
DependenciesListBox.Items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SortLisbox(ListBox listBox)
|
||||||
|
{
|
||||||
|
var sortedItems = listBox.Items.Cast<TextBlock>().OrderBy(x => x.Text).ToList();
|
||||||
|
listBox.Items.Clear();
|
||||||
|
foreach (var item in sortedItems)
|
||||||
|
{
|
||||||
|
listBox.Items.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveDependenciesInstance(string key)
|
||||||
|
{
|
||||||
|
object? itemControl = null;
|
||||||
|
foreach (var item in DependenciesListBox.Items)
|
||||||
|
{
|
||||||
|
if (item is TextBlock block && block.Tag is IOCObj iocObj && iocObj.Key.Equals(key))
|
||||||
|
{
|
||||||
|
itemControl = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (itemControl is not null)
|
||||||
|
{
|
||||||
|
DependenciesListBox.Items.Remove(itemControl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Serein.WorkBench.Themes
|
|
||||||
{
|
|
||||||
internal class IOCObjectViewMoel
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<UserControl x:Class="Serein.WorkBench.Themes.LazyTreeView"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:Serein.WorkBench.Themes"
|
|
||||||
xmlns:converters="clr-namespace:Serein.WorkBench.Tool.Converters"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<converters:TypeToColorConverter x:Key="TypeToColorConverter" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<Grid>
|
|
||||||
<TreeView Name="treeView"
|
|
||||||
SelectedItemChanged="treeView_SelectedItemChanged"
|
|
||||||
ItemsSource="{Binding RootNodes}">
|
|
||||||
<TreeView.ItemTemplate>
|
|
||||||
<HierarchicalDataTemplate ItemsSource="{Binding SuccessorNodes}">
|
|
||||||
<TextBlock Text="{Binding DisplayName}" Foreground="{Binding ControlType, Converter={StaticResource TypeToColorConverter}}" />
|
|
||||||
</HierarchicalDataTemplate>
|
|
||||||
</TreeView.ItemTemplate>
|
|
||||||
</TreeView>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using Serein.Library.Enums;
|
|
||||||
using Serein.NodeFlow.Base;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Controls.Primitives;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace Serein.WorkBench.Themes
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// LazyTreeView.xaml 的交互逻辑
|
|
||||||
/// </summary>
|
|
||||||
public partial class LazyTreeView : UserControl
|
|
||||||
{
|
|
||||||
public ObservableCollection<NodeModelBase> RootNodes { get; set; }
|
|
||||||
|
|
||||||
public LazyTreeView()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
RootNodes = new ObservableCollection<NodeModelBase>();
|
|
||||||
treeView.DataContext = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
|
||||||
{
|
|
||||||
if (e.NewValue is NodeModelBase node)
|
|
||||||
{
|
|
||||||
// 在这里设置 Expanded 事件
|
|
||||||
var treeViewItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(node);
|
|
||||||
treeViewItem.Expanded += (s, args) => LoadChildren(node, treeViewItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void LoadChildren(NodeModelBase node, TreeViewItem treeViewItem)
|
|
||||||
{
|
|
||||||
// 懒加载逻辑
|
|
||||||
if (node.SuccessorNodes.Count > 0)
|
|
||||||
{
|
|
||||||
treeViewItem.Items.Clear();
|
|
||||||
foreach (var child in node.SuccessorNodes[ConnectionType.IsSucceed]) // 根据类型加载子项
|
|
||||||
{
|
|
||||||
treeViewItem.Items.Add(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
52
WorkBench/Themes/NodeTreeItemViewControl.xaml
Normal file
52
WorkBench/Themes/NodeTreeItemViewControl.xaml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<UserControl x:Class="Serein.WorkBench.Themes.NodeTreeItemViewControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Serein.WorkBench.Themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0" x:Name="UpstreamTreeGuid" Margin="0,0,0,0" >
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Rectangle Grid.Column="0" Width="1" x:Name="UpstreamTreeRectangle" Grid.Row="0" Fill="#4A82E4" Margin="4,1,4,1" IsHitTestVisible="False"/>
|
||||||
|
<TreeView Grid.Column="1" x:Name="UpstreamTreeNodes" BorderThickness="0"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1" x:Name="IsSucceedTreeGuid" Margin="0,0,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Rectangle Grid.Column="0" Width="1" x:Name="IsSucceedRectangle" Grid.Row="0" Fill="#04FC10" Margin="4,1,4,1" IsHitTestVisible="False"/>
|
||||||
|
<TreeView Grid.Column="1" x:Name="IsSucceedTreeNodes" BorderThickness="0"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="2" x:Name="IsFailTreeGuid" Margin="0,0,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Rectangle Grid.Column="0" Width="1" x:Name="IsFailRectangle" Grid.Row="0" Fill="#F18905" Margin="4,1,4,1" IsHitTestVisible="False"/>
|
||||||
|
|
||||||
|
<TreeView Grid.Column="1" x:Name="IsFailTreeNodes" BorderThickness="0"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="3" x:Name="IsErrorTreeGuid" Margin="0,0,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Rectangle Grid.Column="0" Width="1" x:Name="IsErrorRectangle" Grid.Row="0" Fill="#FE1343" Margin="4,1,4,1" IsHitTestVisible="False"/>
|
||||||
|
<TreeView Grid.Column="1" x:Name="IsErrorTreeNodes" BorderThickness="0"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
270
WorkBench/Themes/NodeTreeItemViewControl.xaml.cs
Normal file
270
WorkBench/Themes/NodeTreeItemViewControl.xaml.cs
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.Library.Enums;
|
||||||
|
using Serein.NodeFlow;
|
||||||
|
using Serein.NodeFlow.Base;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Controls.Primitives;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using static Serein.WorkBench.Themes.TypeViewerWindow;
|
||||||
|
|
||||||
|
namespace Serein.WorkBench.Themes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NodeTreeVIewControl.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class NodeTreeItemViewControl : UserControl
|
||||||
|
{
|
||||||
|
public NodeTreeItemViewControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
foreach (var ct in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
var guid = ToGridView(this, ct);
|
||||||
|
guid.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存的节点数据
|
||||||
|
/// </summary>
|
||||||
|
private NodeModelBase nodeModel;
|
||||||
|
private IFlowEnvironment flowEnvironment { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private class NodeTreeModel
|
||||||
|
{
|
||||||
|
public NodeModelBase RootNode { get; set; }
|
||||||
|
public Dictionary<ConnectionType, List<NodeModelBase>> ChildNodes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void InitAndLoadTree(IFlowEnvironment flowEnvironment, NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
this.flowEnvironment = flowEnvironment;
|
||||||
|
this.nodeModel = nodeModel;
|
||||||
|
RefreshTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeViewItem RefreshTree()
|
||||||
|
{
|
||||||
|
NodeModelBase rootNodeModel = this.nodeModel;
|
||||||
|
NodeTreeModel nodeTreeModel = new NodeTreeModel
|
||||||
|
{
|
||||||
|
RootNode = rootNodeModel,
|
||||||
|
ChildNodes = new Dictionary<ConnectionType, List<NodeModelBase>>()
|
||||||
|
{
|
||||||
|
{ConnectionType.Upstream, []},
|
||||||
|
{ConnectionType.IsSucceed, [rootNodeModel]},
|
||||||
|
{ConnectionType.IsFail, []},
|
||||||
|
{ConnectionType.IsError, []},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var rootNode = new TreeViewItem
|
||||||
|
{
|
||||||
|
Header = rootNodeModel.MethodDetails.MethodTips,
|
||||||
|
Tag = nodeTreeModel,
|
||||||
|
};
|
||||||
|
LoadNodeItem(this, nodeTreeModel);
|
||||||
|
rootNode.Expanded += TreeViewItem_Expanded; // 监听展开事件
|
||||||
|
rootNode.IsExpanded = true;
|
||||||
|
return rootNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 展开子项事件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is TreeViewItem item && item.Tag is NodeTreeModel nodeTreeModel)
|
||||||
|
{
|
||||||
|
item.Items.Clear();
|
||||||
|
NodeTreeItemViewControl? nodeTreeItemViewControl = LoadTNoderee(nodeTreeModel);
|
||||||
|
|
||||||
|
if (nodeTreeItemViewControl is not null)
|
||||||
|
{
|
||||||
|
LoadNodeItem(nodeTreeItemViewControl, nodeTreeModel);
|
||||||
|
item.Items.Add(nodeTreeItemViewControl);
|
||||||
|
|
||||||
|
}
|
||||||
|
item.IsSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载面板
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeTreeItemViewControl"></param>
|
||||||
|
/// <param name="nodeTreeModel"></param>
|
||||||
|
private void LoadNodeItem(NodeTreeItemViewControl nodeTreeItemViewControl, NodeTreeModel nodeTreeModel)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var ct in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
var treeViewer = ToTreeView(nodeTreeItemViewControl, ct);
|
||||||
|
var guid = ToGridView(nodeTreeItemViewControl, ct);
|
||||||
|
treeViewer.Items.Clear(); // 移除对象树的所有节点
|
||||||
|
var list = nodeTreeModel.ChildNodes[ct];
|
||||||
|
|
||||||
|
if (list.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var child in list)
|
||||||
|
{
|
||||||
|
NodeTreeModel tmpNodeTreeModel = new NodeTreeModel
|
||||||
|
{
|
||||||
|
RootNode = child,
|
||||||
|
ChildNodes = child.SuccessorNodes,
|
||||||
|
};
|
||||||
|
TreeViewItem treeViewItem = new TreeViewItem
|
||||||
|
{
|
||||||
|
Header = child.MethodDetails.MethodTips,
|
||||||
|
Tag = tmpNodeTreeModel
|
||||||
|
};
|
||||||
|
treeViewItem.Expanded += TreeViewItem_Expanded;
|
||||||
|
ContextMenu contextMenu = new ContextMenu();
|
||||||
|
contextMenu.Items.Add(MainWindow.CreateMenuItem("从此节点执行", (s, e) =>
|
||||||
|
{
|
||||||
|
flowEnvironment.StartFlowInSelectNodeAsync(tmpNodeTreeModel.RootNode.Guid);
|
||||||
|
}));
|
||||||
|
treeViewItem.ContextMenu = contextMenu;
|
||||||
|
|
||||||
|
treeViewer.Items.Add(treeViewItem);
|
||||||
|
}
|
||||||
|
guid.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
guid.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载节点子项
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeTreeModel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private NodeTreeItemViewControl? LoadTNoderee(NodeTreeModel nodeTreeModel)
|
||||||
|
{
|
||||||
|
NodeTreeItemViewControl nodeTreeItemViewControl = null;
|
||||||
|
foreach (var connectionType in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
var childNodeModels = nodeTreeModel.ChildNodes[connectionType];
|
||||||
|
if (childNodeModels.Count > 0)
|
||||||
|
{
|
||||||
|
nodeTreeItemViewControl ??= new NodeTreeItemViewControl();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeView treeView = ToTreeView(nodeTreeItemViewControl, connectionType);
|
||||||
|
foreach (var childNodeModel in childNodeModels)
|
||||||
|
{
|
||||||
|
NodeTreeModel tempNodeTreeModel = new NodeTreeModel
|
||||||
|
{
|
||||||
|
RootNode = childNodeModel,
|
||||||
|
ChildNodes = childNodeModel.SuccessorNodes,
|
||||||
|
};
|
||||||
|
TreeViewItem treeViewItem = new TreeViewItem
|
||||||
|
{
|
||||||
|
Header = childNodeModel.MethodDetails.MethodTips,
|
||||||
|
Tag = tempNodeTreeModel
|
||||||
|
};
|
||||||
|
treeViewItem.Margin = new Thickness(-15, 0, 0, 0);
|
||||||
|
treeViewItem.Visibility = Visibility.Visible;
|
||||||
|
treeView.Items.Add(treeViewItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nodeTreeItemViewControl is not null)
|
||||||
|
{
|
||||||
|
foreach (var connectionType in NodeStaticConfig.ConnectionTypes)
|
||||||
|
{
|
||||||
|
var childNodeModels = nodeTreeModel.ChildNodes[connectionType];
|
||||||
|
if (childNodeModels.Count > 0)
|
||||||
|
{
|
||||||
|
nodeTreeItemViewControl ??= new NodeTreeItemViewControl();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeTreeItemViewControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 折叠事件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void TreeViewItem_Collapsed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is TreeViewItem item && item.Items.Count > 0)
|
||||||
|
{
|
||||||
|
item.Items.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static TreeView ToTreeView(NodeTreeItemViewControl item, ConnectionType connectionType)
|
||||||
|
{
|
||||||
|
return connectionType switch
|
||||||
|
{
|
||||||
|
ConnectionType.Upstream => item.UpstreamTreeNodes,
|
||||||
|
ConnectionType.IsError => item.IsErrorTreeNodes,
|
||||||
|
ConnectionType.IsFail => item.IsFailTreeNodes,
|
||||||
|
ConnectionType.IsSucceed => item.IsSucceedTreeNodes,
|
||||||
|
_ => throw new Exception("LoadNodeItem Error :ConnectionType is " + connectionType)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static Grid ToGridView(NodeTreeItemViewControl item, ConnectionType connectionType)
|
||||||
|
{
|
||||||
|
return connectionType switch
|
||||||
|
{
|
||||||
|
ConnectionType.Upstream => item.UpstreamTreeGuid,
|
||||||
|
ConnectionType.IsError => item.IsErrorTreeGuid,
|
||||||
|
ConnectionType.IsFail => item.IsFailTreeGuid,
|
||||||
|
ConnectionType.IsSucceed => item.IsSucceedTreeGuid,
|
||||||
|
_ => throw new Exception("LoadNodeItem Error :ConnectionType is " + connectionType)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static System.Windows.Shapes.Rectangle ToRectangle(NodeTreeItemViewControl item, ConnectionType connectionType)
|
||||||
|
//{
|
||||||
|
// return connectionType switch
|
||||||
|
// {
|
||||||
|
// ConnectionType.Upstream => item.UpstreamTreeRectangle,
|
||||||
|
// ConnectionType.IsError => item.IsErrorRectangle,
|
||||||
|
// ConnectionType.IsFail => item.IsFailRectangle,
|
||||||
|
// ConnectionType.IsSucceed => item.IsSucceedRectangle,
|
||||||
|
// _ => throw new Exception("LoadNodeItem Error :ConnectionType is " + connectionType)
|
||||||
|
// };
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
using Serein.NodeFlow.Base;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Controls.Primitives;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows;
|
|
||||||
using Serein.Library.Enums;
|
|
||||||
|
|
||||||
namespace Serein.WorkBench.Themes
|
|
||||||
{
|
|
||||||
public class NodeTreeView : TreeView
|
|
||||||
{
|
|
||||||
public NodeTreeView()
|
|
||||||
{
|
|
||||||
this.ItemContainerGenerator.StatusChanged += OnStatusChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStatusChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
|
|
||||||
{
|
|
||||||
foreach (var item in Items)
|
|
||||||
{
|
|
||||||
var treeViewItem = (TreeViewItem)this.ItemContainerGenerator.ContainerFromItem(item);
|
|
||||||
if (treeViewItem != null)
|
|
||||||
{
|
|
||||||
treeViewItem.Expanded += TreeViewItem_Expanded;
|
|
||||||
ApplyColor(treeViewItem, item as NodeModelBase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is TreeViewItem item && item.DataContext is NodeModelBase node)
|
|
||||||
{
|
|
||||||
if (item.Items.Count == 0) // 懒加载
|
|
||||||
{
|
|
||||||
foreach (var childNode in node.SuccessorNodes[ConnectionType.Upstream])
|
|
||||||
{
|
|
||||||
item.Items.Add(childNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyColor(TreeViewItem item, NodeModelBase node)
|
|
||||||
{
|
|
||||||
// 根据 ControlType 设置颜色
|
|
||||||
switch (node.ControlType)
|
|
||||||
{
|
|
||||||
case NodeControlType.Flipflop:
|
|
||||||
item.Background = Brushes.LightGreen;
|
|
||||||
break;
|
|
||||||
case NodeControlType.Action:
|
|
||||||
item.Background = Brushes.LightCoral;
|
|
||||||
break;
|
|
||||||
// 添加更多条件
|
|
||||||
default:
|
|
||||||
item.Background = Brushes.Transparent;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
47
WorkBench/Themes/NodeTreeViewControl.xaml
Normal file
47
WorkBench/Themes/NodeTreeViewControl.xaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<UserControl x:Class="Serein.WorkBench.Themes.NodeTreeViewControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Serein.WorkBench.Themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Style x:Key="ListItemNullFocusContainerStyle" TargetType="ListBoxItem">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="true" />
|
||||||
|
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="ListBoxItem">
|
||||||
|
<Border Name="Border" Background="Transparent" SnapsToDevicePixels="True">
|
||||||
|
<ContentPresenter />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="auto"/>
|
||||||
|
<RowDefinition Height="auto"/>
|
||||||
|
<!--<RowDefinition Height="*"/>-->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0">
|
||||||
|
<TextBlock Text="起始节点"/>
|
||||||
|
|
||||||
|
<ScrollViewer >
|
||||||
|
<local:NodeTreeItemViewControl x:Name="StartNodeViewer" Margin="4,4,4,4"/>
|
||||||
|
</ScrollViewer >
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1">
|
||||||
|
<TextBlock Text="全局触发器"/>
|
||||||
|
<ListBox x:Name="GlobalFlipflopNodeListbox" BorderThickness="0" ItemContainerStyle="{StaticResource ListItemNullFocusContainerStyle}"></ListBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!--<StackPanel Grid.Row="2">
|
||||||
|
<TextBlock Text="无业游民"/>
|
||||||
|
<ListBox x:Name="UnreachableNodeListbox" BorderThickness="0" ItemContainerStyle="{StaticResource ListItemNullFocusContainerStyle}"></ListBox>
|
||||||
|
</StackPanel>-->
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
99
WorkBench/Themes/NodeTreeViewControl.xaml.cs
Normal file
99
WorkBench/Themes/NodeTreeViewControl.xaml.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using Serein.Library.Api;
|
||||||
|
using Serein.NodeFlow.Base;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Serein.WorkBench.Themes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NodeTreeViewControl.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class NodeTreeViewControl : UserControl
|
||||||
|
{
|
||||||
|
private IFlowEnvironment FlowEnvironment { get; set; }
|
||||||
|
public NodeTreeViewControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string startNodeGuid = string.Empty;
|
||||||
|
private Dictionary<string, NodeTreeItemViewControl> globalFlipflopNodes = [];
|
||||||
|
private Dictionary<string, NodeTreeItemViewControl> unemployedNodes = [];
|
||||||
|
|
||||||
|
public void LoadNodeTreeOfStartNode(IFlowEnvironment flowEnvironment, NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
startNodeGuid = nodeModel.Guid;
|
||||||
|
StartNodeViewer.InitAndLoadTree(flowEnvironment, nodeModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 触发器
|
||||||
|
public void AddGlobalFlipFlop(IFlowEnvironment flowEnvironment, NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
if (!globalFlipflopNodes.ContainsKey(nodeModel.Guid))
|
||||||
|
{
|
||||||
|
NodeTreeItemViewControl flipflopTreeViewer = new NodeTreeItemViewControl();
|
||||||
|
flipflopTreeViewer.InitAndLoadTree(flowEnvironment, nodeModel);
|
||||||
|
globalFlipflopNodes.Add(nodeModel.Guid, flipflopTreeViewer);
|
||||||
|
GlobalFlipflopNodeListbox.Items.Add(flipflopTreeViewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RefreshGlobalFlipFlop(NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
if (globalFlipflopNodes.TryGetValue(nodeModel.Guid, out var viewer))
|
||||||
|
{
|
||||||
|
viewer.RefreshTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RemoteGlobalFlipFlop(NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
if (globalFlipflopNodes.TryGetValue(nodeModel.Guid, out var viewer))
|
||||||
|
{
|
||||||
|
globalFlipflopNodes.Remove(nodeModel.Guid);
|
||||||
|
GlobalFlipflopNodeListbox.Items.Remove(viewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region 无业游民(定义:不存在于起始节点与全局触发器的调用链上的节点,只能手动刷新?)
|
||||||
|
public void AddUnemployed(IFlowEnvironment flowEnvironment, NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
if (!unemployedNodes.ContainsKey(nodeModel.Guid))
|
||||||
|
{
|
||||||
|
NodeTreeItemViewControl flipflopTreeViewer = new NodeTreeItemViewControl();
|
||||||
|
flipflopTreeViewer.InitAndLoadTree(flowEnvironment, nodeModel);
|
||||||
|
unemployedNodes.Add(nodeModel.Guid, flipflopTreeViewer);
|
||||||
|
GlobalFlipflopNodeListbox.Items.Add(flipflopTreeViewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RefreshUnemployed(NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
if (unemployedNodes.TryGetValue(nodeModel.Guid, out var viewer))
|
||||||
|
{
|
||||||
|
viewer.RefreshTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RemoteUnemployed(NodeModelBase nodeModel)
|
||||||
|
{
|
||||||
|
if (unemployedNodes.TryGetValue(nodeModel.Guid, out var viewer))
|
||||||
|
{
|
||||||
|
unemployedNodes.Remove(nodeModel.Guid);
|
||||||
|
GlobalFlipflopNodeListbox.Items.Remove(viewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,7 +85,7 @@ namespace Serein.WorkBench.Themes
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 监视对象的键
|
/// 监视对象的键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object MonitorKey { get => monitorKey; }
|
public string MonitorKey { get => monitorKey; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 正在监视的对象
|
/// 正在监视的对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,7 +96,7 @@ namespace Serein.WorkBench.Themes
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string MonitorExpression { get => ExpressionTextBox.Text.ToString(); }
|
public string MonitorExpression { get => ExpressionTextBox.Text.ToString(); }
|
||||||
|
|
||||||
private object monitorKey;
|
private string monitorKey;
|
||||||
private object monitorObj;
|
private object monitorObj;
|
||||||
|
|
||||||
// 用于存储当前展开的节点路径
|
// 用于存储当前展开的节点路径
|
||||||
@@ -107,7 +107,7 @@ namespace Serein.WorkBench.Themes
|
|||||||
/// 加载对象信息,展示其成员
|
/// 加载对象信息,展示其成员
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">要展示的对象</param>
|
/// <param name="obj">要展示的对象</param>
|
||||||
public void LoadObjectInformation(object key, object obj)
|
public void LoadObjectInformation(string key, object obj)
|
||||||
{
|
{
|
||||||
if (obj == null) return;
|
if (obj == null) return;
|
||||||
monitorKey = key;
|
monitorKey = key;
|
||||||
@@ -171,6 +171,7 @@ namespace Serein.WorkBench.Themes
|
|||||||
// 这里创建了一个子项,并给这个子项创建了“正在加载”的子项
|
// 这里创建了一个子项,并给这个子项创建了“正在加载”的子项
|
||||||
// 然后移除了原来对象树的所有项,再把这个新创建的子项添加上去
|
// 然后移除了原来对象树的所有项,再把这个新创建的子项添加上去
|
||||||
// 绑定了展开/折叠事件后,自动展开第一层,开始反射obj的成员,并判断obj的成员生成什么样的节点
|
// 绑定了展开/折叠事件后,自动展开第一层,开始反射obj的成员,并判断obj的成员生成什么样的节点
|
||||||
|
rootNode.IsExpanded = true;
|
||||||
return rootNode;
|
return rootNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,6 +455,11 @@ namespace Serein.WorkBench.Themes
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if(obj is null)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
var properties = obj.GetType().GetProperties();
|
var properties = obj.GetType().GetProperties();
|
||||||
|
|
||||||
// 获取实例属性值
|
// 获取实例属性值
|
||||||
|
|||||||
Reference in New Issue
Block a user