重写了节点的view、viewmodel关系,实现了对画布元素的选取功能,重构了底层依赖,添加了对net .Framework4.6.1以上的Framework类库支持

This commit is contained in:
fengjiayi
2024-09-12 20:32:54 +08:00
parent ec6e09ced1
commit f286fc644a
120 changed files with 91218 additions and 761 deletions

View File

@@ -0,0 +1,35 @@
using Serein.Library.Api;
using Serein.Library.Utils;
namespace Serein.Library.Core.NodeFlow
{
/// <summary>
/// 动态流程上下文
/// </summary>
public class DynamicContext: IDynamicContext
{
public DynamicContext(ISereinIoc sereinIoc)
{
SereinIoc = sereinIoc;
}
public NodeRunCts NodeRunCts { get; set; }
public ISereinIoc SereinIoc { get; }
public Task CreateTimingTask(Action action, int time = 100, int count = -1)
{
NodeRunCts ??= SereinIoc.GetOrInstantiate<NodeRunCts>();
return Task.Factory.StartNew(async () =>
{
for (int i = 0; i < count; i++)
{
NodeRunCts.Token.ThrowIfCancellationRequested();
await Task.Delay(time);
action.Invoke();
}
});
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.LibraryCore.NodeFlow
{
public enum DynamicNodeCoreType
{
/// <summary>
/// 初始化
/// </summary>
Init,
/// <summary>
/// 开始载入
/// </summary>
Loading,
/// <summary>
/// 结束
/// </summary>
Exit,
/// <summary>
/// 触发器
/// </summary>
Flipflop,
/// <summary>
/// 条件节点
/// </summary>
Condition,
/// <summary>
/// 动作节点
/// </summary>
Action,
}
}

View File

@@ -0,0 +1,85 @@
using Serein.Library.Api;
using Serein.Library.Enums;
namespace Serein.Library.Core.NodeFlow
{
public static class FlipflopFunc
{
/// <summary>
/// 传入触发器方法的返回类型尝试获取Task[Flipflop[]] 中的泛型类型
/// </summary>
//public static Type GetFlipflopInnerType(Type type)
//{
// // 检查是否为泛型类型且为 Task<>
// if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
// {
// // 获取 Task<> 的泛型参数类型,即 Flipflop<>
// var innerType = type.GetGenericArguments()[0];
// // 检查泛型参数是否为 Flipflop<>
// if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(FlipflopContext<>))
// {
// // 获取 Flipflop<> 的泛型参数类型,即 T
// var flipflopInnerType = innerType.GetGenericArguments()[0];
// // 返回 Flipflop<> 中的具体类型
// return flipflopInnerType;
// }
// }
// // 如果不符合条件,返回 null
// return null;
//}
public static bool IsTaskOfFlipflop(Type type)
{
// 检查是否为泛型类型且为 Task<>
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
{
// 获取 Task<> 的泛型参数类型
var innerType = type.GetGenericArguments()[0];
// 判断 innerType 是否继承 IFlipflopContext
//if (typeof(IFlipflopContext).IsAssignableFrom(innerType))
//{
// return true;
//}
//else
//{
// return false;
//}
// 检查泛型参数是否为 Flipflop<>
if (innerType == typeof(IFlipflopContext))
//if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(FlipflopContext<>))
{
return true;
}
}
return false;
}
}
/// <summary>
/// 触发器上下文
/// </summary>
public class FlipflopContext : IFlipflopContext
{
public FlowStateType State { get; set; }
//public TResult? Data { get; set; }
public object Data { get; set; }
public FlipflopContext(FlowStateType ffState)
{
State = ffState;
}
public FlipflopContext(FlowStateType ffState, object data)
{
State = ffState;
Data = data;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Core.NodeFlow
{
//public enum FlowStateType
//{
// /// <summary>
// /// 成功(方法成功执行)
// /// </summary>
// Succeed,
// /// <summary>
// /// 失败(方法没有成功执行,不过执行时没有发生非预期的错误)
// /// </summary>
// Fail,
// /// <summary>
// /// 异常(节点没有成功执行,执行时发生非预期的错误)
// /// </summary>
// Error,
//}
}

View File

@@ -0,0 +1,35 @@
using Serein.Library.Api.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Core.NodeFlow.Tool
{
/// <summary>
/// 用来判断一个类是否需要注册并构建实例(单例模式场景使用)
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class DynamicFlowAttribute(bool scan = true) : Attribute
{
public bool Scan { get; set; } = scan;
}
/// <summary>
/// 标记一个方法是什么类型加载dll后用来拖拽到画布中
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MethodDetailAttribute(DynamicNodeType methodDynamicType,
string methodTips = "",
bool scan = true,
string lockName = "") : Attribute
{
public bool Scan { get; set; } = scan;
public string MethodTips { get; } = methodTips;
public DynamicNodeType MethodDynamicType { get; } = methodDynamicType;
public string LockName { get; } = lockName;
}
}

View File

@@ -0,0 +1,202 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Core.NodeFlow.Tool
{
#region tsk工具 (
/*public class LockManager
{
private readonly ConcurrentDictionary<string, LockQueue> _locks = new ConcurrentDictionary<string, LockQueue>();
public void CreateLock(string name)
{
_locks.TryAdd(name, new LockQueue());
}
public async Task AcquireLockAsync(string name, CancellationToken cancellationToken = default)
{
if (!_locks.ContainsKey(name))
{
throw new ArgumentException($"Lock with name '{name}' does not exist.");
}
var lockQueue = _locks[name];
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (lockQueue.Queue)
{
lockQueue.Queue.Enqueue(tcs);
if (lockQueue.Queue.Count == 1)
{
tcs.SetResult(true);
}
}
await tcs.Task.ConfigureAwait(false);
// 处理取消操作
if (cancellationToken.CanBeCanceled)
{
cancellationToken.Register(() =>
{
lock (lockQueue.Queue)
{
if (lockQueue.Queue.Contains(tcs))
{
tcs.TrySetCanceled();
}
}
});
}
}
public void ReleaseLock(string name)
{
if (!_locks.ContainsKey(name))
{
throw new ArgumentException($"Lock with name '{name}' does not exist.");
}
var lockQueue = _locks[name];
lock (lockQueue.Queue)
{
if (lockQueue.Queue.Count > 0)
{
lockQueue.Queue.Dequeue();
if (lockQueue.Queue.Count > 0)
{
var next = lockQueue.Queue.Peek();
next.SetResult(true);
}
}
}
}
private class LockQueue
{
public Queue<TaskCompletionSource<bool>> Queue { get; } = new Queue<TaskCompletionSource<bool>>();
}
}
public interface ITaskResult
{
object Result { get; }
}
public class TaskResult<T> : ITaskResult
{
public TaskResult(T result)
{
Result = result;
}
public T Result { get; }
object ITaskResult.Result => Result;
}
public class DynamicTasks
{
private static readonly ConcurrentDictionary<string, Task<ITaskResult>> TaskGuidPairs = new();
public static Task<ITaskResult> GetTask(string Guid)
{
TaskGuidPairs.TryGetValue(Guid, out Task<ITaskResult> task);
return task;
}
public static bool AddTask<T>(string Guid, T result)
{
var task = Task.FromResult<ITaskResult>(new TaskResult<T>(result));
return TaskGuidPairs.TryAdd(Guid, task);
}
}
public class TaskNodeManager
{
private readonly ConcurrentDictionary<string, TaskQueue> _taskQueues = new ConcurrentDictionary<string, TaskQueue>();
public void CreateTaskNode(string name)
{
_taskQueues.TryAdd(name, new TaskQueue());
}
public async Task WaitForTaskNodeAsync(string name, CancellationToken cancellationToken = default)
{
if (!_taskQueues.ContainsKey(name))
{
throw new ArgumentException($"Task node with name '{name}' does not exist.");
}
var taskQueue = _taskQueues[name];
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (taskQueue.Queue)
{
taskQueue.Queue.Enqueue(tcs);
if (taskQueue.Queue.Count == 1)
{
tcs.SetResult(true);
}
}
await tcs.Task.ConfigureAwait(false);
// 处理取消操作
if (cancellationToken.CanBeCanceled)
{
cancellationToken.Register(() =>
{
lock (taskQueue.Queue)
{
if (taskQueue.Queue.Contains(tcs))
{
tcs.TrySetCanceled();
}
}
});
}
}
public void CompleteTaskNode(string name)
{
if (!_taskQueues.ContainsKey(name))
{
throw new ArgumentException($"Task node with name '{name}' does not exist.");
}
var taskQueue = _taskQueues[name];
lock (taskQueue.Queue)
{
if (taskQueue.Queue.Count > 0)
{
taskQueue.Queue.Dequeue();
if (taskQueue.Queue.Count > 0)
{
var next = taskQueue.Queue.Peek();
next.SetResult(true);
}
}
}
}
private class TaskQueue
{
public Queue<TaskCompletionSource<bool>> Queue { get; } = new Queue<TaskCompletionSource<bool>>();
}
}*/
#endregion
}