diff --git a/Library.Framework/Serein.Library.Framework.csproj b/Library.Framework/Serein.Library.Framework.csproj index 5332cb5..5d7f938 100644 --- a/Library.Framework/Serein.Library.Framework.csproj +++ b/Library.Framework/Serein.Library.Framework.csproj @@ -9,7 +9,7 @@ Properties Serein.Library.Framework Serein.Library.Framework - v4.6.1 + v4.6.2 512 true diff --git a/Library/Serein.Library.csproj b/Library/Serein.Library.csproj index 8f12865..cfe4b49 100644 --- a/Library/Serein.Library.csproj +++ b/Library/Serein.Library.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net461 + netstandard2.0;net462 D:\Project\C#\DynamicControl\SereinFlow\.Output diff --git a/Library/Utils/ChannelFlowInterrupt.cs b/Library/Utils/ChannelFlowInterrupt.cs index c8e1402..d6fe5f0 100644 --- a/Library/Utils/ChannelFlowInterrupt.cs +++ b/Library/Utils/ChannelFlowInterrupt.cs @@ -7,196 +7,193 @@ using System.Threading.Tasks; namespace Serein.Library.Utils { -/// -/// 流程中断管理 -/// -public class ChannelFlowInterrupt -{ - - - -/// -/// 中断取消类型 -/// -public enum CancelType -{ - Manual, - Error, - Overtime -} - -// 使用并发字典管理每个信号对应的 Channel -private readonly ConcurrentDictionary> _channels = new ConcurrentDictionary>(); - -/// -/// 创建信号并指定超时时间,到期后自动触发(异步方法) -/// -/// 信号标识符 -/// 超时时间 -/// 等待任务 -public async Task GetCreateChannelWithTimeoutAsync(string signal, TimeSpan outTime) -{ - var channel = GetOrCreateChannel(signal); - var cts = new CancellationTokenSource(); - - // 异步任务:超时后自动触发信号 - _ = Task.Run(async () => + /// + /// 流程中断管理 + /// + public class ChannelFlowInterrupt { - try + /// + /// 中断取消类型 + /// + public enum CancelType { - await Task.Delay(outTime, cts.Token); - if (!cts.Token.IsCancellationRequested) + Manual, + Error, + Overtime + } + + // 使用并发字典管理每个信号对应的 Channel + private readonly ConcurrentDictionary> _channels = new ConcurrentDictionary>(); + + /// + /// 创建信号并指定超时时间,到期后自动触发(异步方法) + /// + /// 信号标识符 + /// 超时时间 + /// 等待任务 + public async Task GetCreateChannelWithTimeoutAsync(string signal, TimeSpan outTime) + { + var channel = GetOrCreateChannel(signal); + var cts = new CancellationTokenSource(); + + // 异步任务:超时后自动触发信号 + _ = Task.Run(async () => { - await channel.Writer.WriteAsync(CancelType.Overtime); + try + { + await Task.Delay(outTime, cts.Token); + if (!cts.Token.IsCancellationRequested) + { + await channel.Writer.WriteAsync(CancelType.Overtime); + } + } + catch (OperationCanceledException) + { + // 超时任务被取消 + } + finally + { + cts?.Dispose(); + } + }, cts.Token); + + // 等待信号传入(超时或手动触发) + try + { + var result = await channel.Reader.ReadAsync(); + return result; } + catch + { + return CancelType.Error; + } + } - catch (OperationCanceledException) - { - // 超时任务被取消 - } - finally - { - cts?.Dispose(); - } - }, cts.Token); - - // 等待信号传入(超时或手动触发) - try - { - var result = await channel.Reader.ReadAsync(); - return result; - } - catch - { - return CancelType.Error; - } - -} -/// -/// 创建信号,直到手动触发(异步方法) -/// -/// 信号标识符 -/// 超时时间 -/// 等待任务 -public async Task GetOrCreateChannelAsync(string signal) -{ - try - { - var channel = GetOrCreateChannel(signal); - // 等待信号传入(超时或手动触发) - var result = await channel.Reader.ReadAsync(); - return result; - } - catch - { - return CancelType.Manual; - } -} - -/// -/// 创建信号并指定超时时间,到期后自动触发(同步阻塞方法) -/// -/// 信号标识符 -/// 超时时间 -public CancelType CreateChannelWithTimeoutSync(string signal, TimeSpan timeout) -{ - var channel = GetOrCreateChannel(signal); - var cts = new CancellationTokenSource(); - CancellationToken token = cts.Token; - - // 异步任务:超时后自动触发信号 - _ = Task.Run(async () => + /// + /// 创建信号,直到手动触发(异步方法) + /// + /// 信号标识符 + /// 超时时间 + /// 等待任务 + public async Task GetOrCreateChannelAsync(string signal) { try { - await Task.Delay(timeout, token); - await channel.Writer.WriteAsync(CancelType.Overtime); + var channel = GetOrCreateChannel(signal); + // 等待信号传入(超时或手动触发) + var result = await channel.Reader.ReadAsync(); + return result; } - catch (OperationCanceledException ex) + catch { - // 任务被取消 - await Console.Out.WriteLineAsync(ex.Message); + return CancelType.Manual; } - }); - - // 同步阻塞直到信号触发或超时 - var result = channel.Reader.ReadAsync().AsTask().GetAwaiter().GetResult(); - return result; - -} - -/// -/// 触发信号 -/// -/// 信号字符串 -/// 是否成功触发 -public bool TriggerSignal(string signal) -{ - //if (_channels.TryGetValue(signal, out var channel)) - //{ - // // 手动触发信号 - // channel.Writer.TryWrite(CancelType.Manual); - // return true; - //} - //return false; - - - try - { - if (_channels.TryGetValue(signal, out var channel)) - { - // 手动触发信号 - channel.Writer.TryWrite(CancelType.Manual); - - // 完成写入,标记该信号通道不再接受新写入 - channel.Writer.Complete(); - - // 触发后移除信号 - _channels.TryRemove(signal, out _); - - return true; } - return false; - } - catch - { - return false; - } - -} - -/// -/// 取消所有任务 -/// -public void CancelAllTasks() -{ - foreach (var channel in _channels.Values) - { - try - { - channel.Writer.Complete(); - } - finally + /// + /// 创建信号并指定超时时间,到期后自动触发(同步阻塞方法) + /// + /// 信号标识符 + /// 超时时间 + public CancelType CreateChannelWithTimeoutSync(string signal, TimeSpan timeout) { + var channel = GetOrCreateChannel(signal); + var cts = new CancellationTokenSource(); + CancellationToken token = cts.Token; + + // 异步任务:超时后自动触发信号 + _ = Task.Run(async () => + { + try + { + await Task.Delay(timeout, token); + await channel.Writer.WriteAsync(CancelType.Overtime); + } + catch (OperationCanceledException ex) + { + // 任务被取消 + await Console.Out.WriteLineAsync(ex.Message); + } + }); + + // 同步阻塞直到信号触发或超时 + var result = channel.Reader.ReadAsync().AsTask().GetAwaiter().GetResult(); + return result; } - } - _channels.Clear(); -} -/// -/// 获取或创建指定信号的 Channel -/// -/// 信号字符串 -/// 对应的 Channel -private Channel GetOrCreateChannel(string signal) -{ - return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded()); -} -} + /// + /// 触发信号 + /// + /// 信号字符串 + /// 是否成功触发 + public bool TriggerSignal(string signal) + { + //if (_channels.TryGetValue(signal, out var channel)) + //{ + // // 手动触发信号 + // channel.Writer.TryWrite(CancelType.Manual); + // return true; + //} + //return false; + + + try + { + if (_channels.TryGetValue(signal, out var channel)) + { + // 手动触发信号 + channel.Writer.TryWrite(CancelType.Manual); + + // 完成写入,标记该信号通道不再接受新写入 + channel.Writer.Complete(); + + // 触发后移除信号 + _channels.TryRemove(signal, out _); + + return true; + } + return false; + } + catch + { + + return false; + } + + } + + /// + /// 取消所有任务 + /// + public void CancelAllTasks() + { + foreach (var channel in _channels.Values) + { + try + { + channel.Writer.Complete(); + } + finally + { + + } + } + _channels.Clear(); + } + + /// + /// 获取或创建指定信号的 Channel + /// + /// 信号字符串 + /// 对应的 Channel + private Channel GetOrCreateChannel(string signal) + { + return _channels.GetOrAdd(signal, _ => Channel.CreateUnbounded()); + } + } } #endregion diff --git a/Library/Web/Router.cs b/Library/Web/Router.cs index a7318f3..15c1cfb 100644 --- a/Library/Web/Router.cs +++ b/Library/Web/Router.cs @@ -345,6 +345,7 @@ namespace Serein.Library.Web } catch (JsonReaderException ex) { + Console.WriteLine(ex); return value; } catch (JsonSerializationException ex) diff --git a/Net461DllTest/Device/PrakingDevice.cs b/Net462DllTest/Device/PrakingDevice.cs similarity index 81% rename from Net461DllTest/Device/PrakingDevice.cs rename to Net462DllTest/Device/PrakingDevice.cs index e5b50aa..a76cf8b 100644 --- a/Net461DllTest/Device/PrakingDevice.cs +++ b/Net462DllTest/Device/PrakingDevice.cs @@ -1,4 +1,4 @@ -using Net461DllTest.LogicControl; +using Net462DllTest.LogicControl; using Serein.Library.Attributes; using Serein.Library.NodeFlow.Tool; using System; @@ -7,7 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.Device +namespace Net462DllTest.Device { [AutoRegister] public class PrakingDevice : ChannelFlowTrigger diff --git a/Net461DllTest/Device/SiemensPlcDevice.cs b/Net462DllTest/Device/SiemensPlcDevice.cs similarity index 99% rename from Net461DllTest/Device/SiemensPlcDevice.cs rename to Net462DllTest/Device/SiemensPlcDevice.cs index 4c711c6..2418fb9 100644 --- a/Net461DllTest/Device/SiemensPlcDevice.cs +++ b/Net462DllTest/Device/SiemensPlcDevice.cs @@ -1,13 +1,13 @@ using IoTClient; using IoTClient.Clients.PLC; using IoTClient.Enums; -using Net461DllTest.Enums; -using Net461DllTest.Signal; +using Net462DllTest.Enums; +using Net462DllTest.Signal; using Serein.Library.Attributes; using Serein.Library.NodeFlow.Tool; using System; -namespace Net461DllTest.Device +namespace Net462DllTest.Device { /// diff --git a/Net461DllTest/Enums/FromValue.cs b/Net462DllTest/Enums/FromValue.cs similarity index 85% rename from Net461DllTest/Enums/FromValue.cs rename to Net462DllTest/Enums/FromValue.cs index 70cafbb..4bd6eda 100644 --- a/Net461DllTest/Enums/FromValue.cs +++ b/Net462DllTest/Enums/FromValue.cs @@ -1,4 +1,4 @@ -using Net461DllTest.View; +using Net462DllTest.View; using Serein.Library.Attributes; using System; using System.Collections.Generic; @@ -6,7 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.Signal +namespace Net462DllTest.Signal { public enum FromValue { diff --git a/Net461DllTest/Enums/PlcState.cs b/Net462DllTest/Enums/PlcState.cs similarity index 94% rename from Net461DllTest/Enums/PlcState.cs rename to Net462DllTest/Enums/PlcState.cs index 12e4eed..52a7be5 100644 --- a/Net461DllTest/Enums/PlcState.cs +++ b/Net462DllTest/Enums/PlcState.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.Enums +namespace Net462DllTest.Enums { public enum PlcState { diff --git a/Net461DllTest/Enums/PlcVarEnum.cs b/Net462DllTest/Enums/PlcVarEnum.cs similarity index 96% rename from Net461DllTest/Enums/PlcVarEnum.cs rename to Net462DllTest/Enums/PlcVarEnum.cs index 2ccaaf8..9c85f3f 100644 --- a/Net461DllTest/Enums/PlcVarEnum.cs +++ b/Net462DllTest/Enums/PlcVarEnum.cs @@ -1,12 +1,12 @@ -using Net461DllTest.Signal; +using Net462DllTest.Signal; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using static Net461DllTest.Signal.PlcValueAttribute; +using static Net462DllTest.Signal.PlcValueAttribute; -namespace Net461DllTest.Enums +namespace Net462DllTest.Enums { diff --git a/Net461DllTest/LogicControl/ParkingLogicControl.cs b/Net462DllTest/LogicControl/ParkingLogicControl.cs similarity index 94% rename from Net461DllTest/LogicControl/ParkingLogicControl.cs rename to Net462DllTest/LogicControl/ParkingLogicControl.cs index 0b011cb..200309d 100644 --- a/Net461DllTest/LogicControl/ParkingLogicControl.cs +++ b/Net462DllTest/LogicControl/ParkingLogicControl.cs @@ -1,6 +1,6 @@ -using Net461DllTest.Device; -using Net461DllTest.Signal; -using Net461DllTest.ViewModel; +using Net462DllTest.Device; +using Net462DllTest.Signal; +using Net462DllTest.ViewModel; using Serein.Library.Api; using Serein.Library.Attributes; using Serein.Library.Enums; @@ -13,7 +13,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.LogicControl +namespace Net462DllTest.LogicControl { public enum ParkingCommand diff --git a/Net461DllTest/LogicControl/PlcLogicControl.cs b/Net462DllTest/LogicControl/PlcLogicControl.cs similarity index 97% rename from Net461DllTest/LogicControl/PlcLogicControl.cs rename to Net462DllTest/LogicControl/PlcLogicControl.cs index 07caa0a..6624f20 100644 --- a/Net461DllTest/LogicControl/PlcLogicControl.cs +++ b/Net462DllTest/LogicControl/PlcLogicControl.cs @@ -1,9 +1,9 @@ using IoTClient.Clients.PLC; using IoTClient.Common.Enums; -using Net461DllTest.Device; -using Net461DllTest.Enums; -using Net461DllTest.Signal; -using Net461DllTest.Web; +using Net462DllTest.Device; +using Net462DllTest.Enums; +using Net462DllTest.Signal; +using Net462DllTest.Web; using Serein.Library.Api; using Serein.Library.Attributes; using Serein.Library.Enums; @@ -18,7 +18,7 @@ using System.ComponentModel; using System.Reflection; using System.Threading.Tasks; -namespace Net461DllTest.LogicControl +namespace Net462DllTest.LogicControl { [AutoRegister] [DynamicFlow] diff --git a/Net461DllTest/LogicControl/ViewLogicControl.cs b/Net462DllTest/LogicControl/ViewLogicControl.cs similarity index 95% rename from Net461DllTest/LogicControl/ViewLogicControl.cs rename to Net462DllTest/LogicControl/ViewLogicControl.cs index 15aa626..6a47e59 100644 --- a/Net461DllTest/LogicControl/ViewLogicControl.cs +++ b/Net462DllTest/LogicControl/ViewLogicControl.cs @@ -1,6 +1,6 @@ -using Net461DllTest.Device; -using Net461DllTest.Signal; -using Net461DllTest.ViewModel; +using Net462DllTest.Device; +using Net462DllTest.Signal; +using Net462DllTest.ViewModel; using Serein.Library.Api; using Serein.Library.Attributes; using Serein.Library.Enums; @@ -10,7 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Forms; -namespace Net461DllTest.LogicControl +namespace Net462DllTest.LogicControl { /// diff --git a/Net461DllTest/Net461DllTest.csproj b/Net462DllTest/Net462DllTest.csproj similarity index 97% rename from Net461DllTest/Net461DllTest.csproj rename to Net462DllTest/Net462DllTest.csproj index 05d0107..50a2c4a 100644 --- a/Net461DllTest/Net461DllTest.csproj +++ b/Net462DllTest/Net462DllTest.csproj @@ -6,9 +6,9 @@ AnyCPU {E40EE629-1A38-4011-88E3-9AD036869987} Library - Net461DllTest - Net461DllTest - v4.6.1 + Net462DllTest + Net462DllTest + v4.6.2 512 true true diff --git a/Net461DllTest/Signal/CommandSignal.cs b/Net462DllTest/Signal/CommandSignal.cs similarity index 86% rename from Net461DllTest/Signal/CommandSignal.cs rename to Net462DllTest/Signal/CommandSignal.cs index c8dfe50..98d0577 100644 --- a/Net461DllTest/Signal/CommandSignal.cs +++ b/Net462DllTest/Signal/CommandSignal.cs @@ -1,4 +1,4 @@ -namespace Net461DllTest.Signal +namespace Net462DllTest.Signal { public enum CommandSignal { diff --git a/Net461DllTest/Signal/PLCVarSignal.cs b/Net462DllTest/Signal/PLCVarSignal.cs similarity index 94% rename from Net461DllTest/Signal/PLCVarSignal.cs rename to Net462DllTest/Signal/PLCVarSignal.cs index 9cb5a1c..e618fc0 100644 --- a/Net461DllTest/Signal/PLCVarSignal.cs +++ b/Net462DllTest/Signal/PLCVarSignal.cs @@ -1,8 +1,8 @@ using Serein.Library.Attributes; using System; -using static Net461DllTest.Signal.PlcValueAttribute; +using static Net462DllTest.Signal.PlcValueAttribute; -namespace Net461DllTest.Signal +namespace Net462DllTest.Signal { [AttributeUsage(AttributeTargets.Field)] diff --git a/Net461DllTest/Utils/ToValue.cs b/Net462DllTest/Utils/ToValue.cs similarity index 99% rename from Net461DllTest/Utils/ToValue.cs rename to Net462DllTest/Utils/ToValue.cs index db045ff..aea18bd 100644 --- a/Net461DllTest/Utils/ToValue.cs +++ b/Net462DllTest/Utils/ToValue.cs @@ -1,7 +1,7 @@ using IoTClient; using IoTClient.Clients.PLC; using IoTClient.Enums; -using Net461DllTest.Signal; +using Net462DllTest.Signal; using System; using System.Collections.Generic; using System.Linq; @@ -9,7 +9,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.Utils +namespace Net462DllTest.Utils { internal static class MyPlcExtension { diff --git a/Net461DllTest/View/FromWorkBenchView.Designer.cs b/Net462DllTest/View/FromWorkBenchView.Designer.cs similarity index 99% rename from Net461DllTest/View/FromWorkBenchView.Designer.cs rename to Net462DllTest/View/FromWorkBenchView.Designer.cs index caffe5e..451cd10 100644 --- a/Net461DllTest/View/FromWorkBenchView.Designer.cs +++ b/Net462DllTest/View/FromWorkBenchView.Designer.cs @@ -1,4 +1,4 @@ -namespace Net461DllTest +namespace Net462DllTest { partial class FromWorkBenchView { diff --git a/Net461DllTest/View/FromWorkBenchView.cs b/Net462DllTest/View/FromWorkBenchView.cs similarity index 93% rename from Net461DllTest/View/FromWorkBenchView.cs rename to Net462DllTest/View/FromWorkBenchView.cs index ac47216..ad95f4b 100644 --- a/Net461DllTest/View/FromWorkBenchView.cs +++ b/Net462DllTest/View/FromWorkBenchView.cs @@ -1,6 +1,6 @@ -using Net461DllTest.Device; -using Net461DllTest.Signal; -using Net461DllTest.ViewModel; +using Net462DllTest.Device; +using Net462DllTest.Signal; +using Net462DllTest.ViewModel; using Serein.Library.Api; using Serein.Library.Attributes; using System; @@ -13,7 +13,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -namespace Net461DllTest +namespace Net462DllTest { public partial class FromWorkBenchView : Form { diff --git a/Net461DllTest/View/FromWorkBenchView.resx b/Net462DllTest/View/FromWorkBenchView.resx similarity index 100% rename from Net461DllTest/View/FromWorkBenchView.resx rename to Net462DllTest/View/FromWorkBenchView.resx diff --git a/Net461DllTest/View/TestFormView.Designer.cs b/Net462DllTest/View/TestFormView.Designer.cs similarity index 98% rename from Net461DllTest/View/TestFormView.Designer.cs rename to Net462DllTest/View/TestFormView.Designer.cs index 41ea4a4..a27664b 100644 --- a/Net461DllTest/View/TestFormView.Designer.cs +++ b/Net462DllTest/View/TestFormView.Designer.cs @@ -1,6 +1,6 @@ using System; -namespace Net461DllTest.View +namespace Net462DllTest.View { partial class TestFormView { diff --git a/Net461DllTest/View/TestFormView.cs b/Net462DllTest/View/TestFormView.cs similarity index 90% rename from Net461DllTest/View/TestFormView.cs rename to Net462DllTest/View/TestFormView.cs index b747544..9fb49f3 100644 --- a/Net461DllTest/View/TestFormView.cs +++ b/Net462DllTest/View/TestFormView.cs @@ -1,7 +1,7 @@ using System; using System.Windows.Forms; -namespace Net461DllTest.View +namespace Net462DllTest.View { public partial class TestFormView : Form { diff --git a/Net461DllTest/View/TestFormView.resx b/Net462DllTest/View/TestFormView.resx similarity index 100% rename from Net461DllTest/View/TestFormView.resx rename to Net462DllTest/View/TestFormView.resx diff --git a/Net461DllTest/ViewModel/FromWorkBenchViewModel.cs b/Net462DllTest/ViewModel/FromWorkBenchViewModel.cs similarity index 88% rename from Net461DllTest/ViewModel/FromWorkBenchViewModel.cs rename to Net462DllTest/ViewModel/FromWorkBenchViewModel.cs index 0c0fed2..38f3456 100644 --- a/Net461DllTest/ViewModel/FromWorkBenchViewModel.cs +++ b/Net462DllTest/ViewModel/FromWorkBenchViewModel.cs @@ -1,5 +1,5 @@ -using Net461DllTest.Device; -using Net461DllTest.Signal; +using Net462DllTest.Device; +using Net462DllTest.Signal; using Serein.Library.Attributes; using System; using System.Collections.Generic; @@ -7,7 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.ViewModel +namespace Net462DllTest.ViewModel { public class FromWorkBenchViewModel { diff --git a/Net461DllTest/Web/CommandController.cs b/Net462DllTest/Web/CommandController.cs similarity index 100% rename from Net461DllTest/Web/CommandController.cs rename to Net462DllTest/Web/CommandController.cs diff --git a/Net461DllTest/Web/CommandController_1.cs b/Net462DllTest/Web/CommandController_1.cs similarity index 92% rename from Net461DllTest/Web/CommandController_1.cs rename to Net462DllTest/Web/CommandController_1.cs index d4fc1c8..c840e00 100644 --- a/Net461DllTest/Web/CommandController_1.cs +++ b/Net462DllTest/Web/CommandController_1.cs @@ -1,5 +1,5 @@ -using Net461DllTest.Device; -using Net461DllTest.Signal; +using Net462DllTest.Device; +using Net462DllTest.Signal; using Serein.Library.Attributes; using Serein.Library.Web; using System; @@ -8,7 +8,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Net461DllTest.Web +namespace Net462DllTest.Web { [AutoHosting] public class CommandController : ControllerBase diff --git a/Net461DllTest/app.config b/Net462DllTest/app.config similarity index 61% rename from Net461DllTest/app.config rename to Net462DllTest/app.config index dd1ad41..7a0cd6f 100644 --- a/Net461DllTest/app.config +++ b/Net462DllTest/app.config @@ -1,11 +1,11 @@ - + - - + + - \ No newline at end of file + diff --git a/Net461DllTest/packages.config b/Net462DllTest/packages.config similarity index 100% rename from Net461DllTest/packages.config rename to Net462DllTest/packages.config diff --git a/NodeFlow/Base/NodeModelBaseData.cs b/NodeFlow/Base/NodeModelBaseData.cs index 115b2d5..b8de691 100644 --- a/NodeFlow/Base/NodeModelBaseData.cs +++ b/NodeFlow/Base/NodeModelBaseData.cs @@ -41,12 +41,12 @@ namespace Serein.NodeFlow.Base /// /// 节点guid /// - public string Guid { get; set; } + public string Guid { get; set; } = string.Empty; /// /// 显示名称 /// - public string DisplayName { get; set; } + public string DisplayName { get; set; } = string.Empty; /// /// 是否为起点控件 @@ -76,7 +76,7 @@ namespace Serein.NodeFlow.Base /// /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值) /// - public Exception RuningException { get; set; } = null; + public Exception? RuningException { get; set; } = null; /// diff --git a/NodeFlow/Base/NodeModelBaseFunc.cs b/NodeFlow/Base/NodeModelBaseFunc.cs index e7178f8..c788f90 100644 --- a/NodeFlow/Base/NodeModelBaseFunc.cs +++ b/NodeFlow/Base/NodeModelBaseFunc.cs @@ -74,17 +74,17 @@ namespace Serein.NodeFlow.Base internal virtual NodeModelBase LoadInfo(NodeInfo nodeInfo) { - var node = this; - if (node != null) + this.Guid = nodeInfo.Guid; + if(this.MethodDetails is not null) { - node.Guid = nodeInfo.Guid; for (int i = 0; i < nodeInfo.ParameterData.Length; i++) { Parameterdata? pd = nodeInfo.ParameterData[i]; - node.MethodDetails.ExplicitDatas[i].IsExplicitData = pd.State; - node.MethodDetails.ExplicitDatas[i].DataValue = pd.Value; + this.MethodDetails.ExplicitDatas[i].IsExplicitData = pd.State; + this.MethodDetails.ExplicitDatas[i].DataValue = pd.Value; } } + return this; } @@ -132,7 +132,7 @@ namespace Serein.NodeFlow.Base if (upstreamNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前 { var cancelType = await upstreamNodes[i].DebugSetting.GetInterruptTask(); - await Console.Out.WriteLineAsync($"[{upstreamNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支"); + await Console.Out.WriteLineAsync($"[{upstreamNodes[i]?.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); } upstreamNodes[i].PreviousNode = currentNode; await upstreamNodes[i].StartExecute(context); // 执行流程节点的上游分支 @@ -165,7 +165,7 @@ namespace Serein.NodeFlow.Base if (nextNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前 { var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask(); - await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支"); + await Console.Out.WriteLineAsync($"[{nextNodes[i]?.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); } nextNodes[i].PreviousNode = currentNode; stack.Push(nextNodes[i]); @@ -194,18 +194,22 @@ namespace Serein.NodeFlow.Base // this.NextOrientation = ConnectionType.None; // return null; //} - await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支"); + await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支"); } #endregion - MethodDetails md = MethodDetails; + MethodDetails? md = MethodDetails; //var del = md.MethodDelegate.Clone(); + if (md is null) + { + throw new Exception($"节点{this.Guid}不存在方法信息,请检查是否需要重写节点的ExecutingAsync"); + } if (!context.Env.TryGetDelegate(md.MethodName, out var del)) { - throw new Exception("不存在对应委托"); + throw new Exception($"节点{this.Guid}不存在对应委托"); } - md.ActingInstance ??= context.Env.IOC.Get(MethodDetails.ActingInstanceType); + md.ActingInstance ??= context.Env.IOC.Get(md.ActingInstanceType); object instance = md.ActingInstance; var haveParameter = md.ExplicitDatas.Length > 0; @@ -281,7 +285,7 @@ namespace Serein.NodeFlow.Base if (ed.IsExplicitData) // 判断是否使用显示的输入参数 { - if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase)) + if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) && flowData is not null) { // 执行表达式从上一节点获取对象 inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, flowData, out _); @@ -315,8 +319,6 @@ namespace Serein.NodeFlow.Base } } - //var attribute = ed.DataType.GetCustomAttribute(); - //if (attribute is not null && attribute.EnumType.IsEnum) // 获取枚举转换器中记录的枚举 if ( ed.DataType != ed.ExplicitType) // 获取枚举转换器中记录的枚举 { if (ed.ExplicitType.IsEnum && Enum.TryParse(ed.ExplicitType, ed.DataValue, out var resultEnum)) // 获取对应的枚举项 @@ -339,41 +341,43 @@ namespace Serein.NodeFlow.Base try { + string? valueStr = inputParameter?.ToString(); parameters[i] = ed.DataType switch { - //Type t when t == previousDataType => inputParameter, // 上下文 - Type t when t.IsEnum => Enum.Parse(ed.DataType, ed.DataValue),// 需要枚举 Type t when t == typeof(IDynamicContext) => context, // 上下文 + Type t when t.IsEnum => Enum.Parse(ed.DataType, ed.DataValue),// 需要枚举 + Type t when t == typeof(string) => inputParameter?.ToString(), + Type t when t == typeof(char) && !string.IsNullOrEmpty(valueStr) => char.Parse(valueStr), + Type t when t == typeof(bool) && !string.IsNullOrEmpty(valueStr) => inputParameter is not null && bool.Parse(valueStr), + Type t when t == typeof(float) && !string.IsNullOrEmpty(valueStr) => float.Parse(valueStr), + Type t when t == typeof(decimal) && !string.IsNullOrEmpty(valueStr) => decimal.Parse(valueStr), + Type t when t == typeof(double) && !string.IsNullOrEmpty(valueStr) => double.Parse(valueStr), + Type t when t == typeof(sbyte) && !string.IsNullOrEmpty(valueStr) => sbyte.Parse(valueStr), + Type t when t == typeof(byte) && !string.IsNullOrEmpty(valueStr) => byte.Parse(valueStr), + Type t when t == typeof(short) && !string.IsNullOrEmpty(valueStr) => short.Parse(valueStr), + Type t when t == typeof(ushort) && !string.IsNullOrEmpty(valueStr) => ushort.Parse(valueStr), + Type t when t == typeof(int) && !string.IsNullOrEmpty(valueStr) => int.Parse(valueStr), + Type t when t == typeof(uint) && !string.IsNullOrEmpty(valueStr) => uint.Parse(valueStr), + Type t when t == typeof(long) && !string.IsNullOrEmpty(valueStr) => long.Parse(valueStr), + Type t when t == typeof(ulong) && !string.IsNullOrEmpty(valueStr) => ulong.Parse(valueStr), + Type t when t == typeof(nint) && !string.IsNullOrEmpty(valueStr) => nint.Parse(valueStr), + Type t when t == typeof(nuint) && !string.IsNullOrEmpty(valueStr) => nuint.Parse(valueStr), + //Type t when t == typeof(DateTime) => string.IsNullOrEmpty(valueStr) ? 0 : DateTime.Parse(valueStr), + Type t when t == typeof(MethodDetails) => md, // 节点方法描述 Type t when t == typeof(NodeModelBase) => nodeModel, // 节点实体类 - Type t when t == typeof(Guid) => new Guid(inputParameter?.ToString()), - Type t when t == typeof(DateTime) => DateTime.Parse(inputParameter?.ToString()), - Type t when t == typeof(string) => inputParameter?.ToString(), - Type t when t == typeof(char) => char.Parse(inputParameter?.ToString()), - Type t when t == typeof(bool) => inputParameter is null ? false : bool.Parse(inputParameter?.ToString()), - Type t when t == typeof(float) => inputParameter is null ? 0F : float.Parse(inputParameter?.ToString()), - Type t when t == typeof(decimal) => inputParameter is null ? 0 : decimal.Parse(inputParameter?.ToString()), - Type t when t == typeof(double) => inputParameter is null ? 0 : double.Parse(inputParameter?.ToString()), - Type t when t == typeof(sbyte) => inputParameter is null ? 0 : sbyte.Parse(inputParameter?.ToString()), - Type t when t == typeof(byte) => inputParameter is null ? 0 : byte.Parse(inputParameter?.ToString()), - Type t when t == typeof(short) => inputParameter is null ? 0 : short.Parse(inputParameter?.ToString()), - Type t when t == typeof(ushort) => inputParameter is null ? 0U : ushort.Parse(inputParameter?.ToString()), - Type t when t == typeof(int) => inputParameter is null ? 0 : int.Parse(inputParameter?.ToString()), - Type t when t == typeof(uint) => inputParameter is null ? 0U : uint.Parse(inputParameter?.ToString()), - Type t when t == typeof(long) => inputParameter is null ? 0L : long.Parse(inputParameter?.ToString()), - Type t when t == typeof(ulong) => inputParameter is null ? 0UL : ulong.Parse(inputParameter?.ToString()), - Type t when t == typeof(nint) => inputParameter is null ? 0 : nint.Parse(inputParameter?.ToString()), - Type t when t == typeof(nuint) => inputParameter is null ? 0 : nuint.Parse(inputParameter?.ToString()), Type t when t.IsArray => (inputParameter as Array)?.Cast().ToList(), Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>) => inputParameter, - Type t when Nullable.GetUnderlyingType(t) != null => inputParameter is null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)), _ => inputParameter, + // Type t when Nullable.GetUnderlyingType(t) != null => inputParameter is null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)), }; + + } catch (Exception ex) // 节点参数类型转换异常 { - parameters[i] = null; + parameters[i] = new object(); Console.WriteLine(ex); } } @@ -395,21 +399,25 @@ 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 monitorType) { MonitorObjectEventArgs.ObjSourceType sourceType; - string key; - if(type == 0) + string? key; + if(monitorType == 0) { - key = data.GetType().FullName; + key = data?.GetType()?.FullName; sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj; } else { key = nodeModel.Guid; sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj; - } + if (string.IsNullOrEmpty(key)) + { + return; + } + if (context.Env.CheckObjMonitorState(key, out List exps)) // 如果新的数据处于查看状态,通知UI进行更新?交给运行环境判断? { context.Env.MonitorObjectNotification(nodeModel.Guid, data, sourceType); // 对象处于监视状态,通知UI更新数据显示 diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs index c8887ca..e7b2597 100644 --- a/NodeFlow/FlowEnvironment.cs +++ b/NodeFlow/FlowEnvironment.cs @@ -46,7 +46,7 @@ namespace Serein.NodeFlow public FlowEnvironment() { sereinIOC = new SereinIOC(); - //ChannelFlowInterrupt = new ChannelFlowInterrupt(); + ChannelFlowInterrupt = new ChannelFlowInterrupt(); //LoadedAssemblyPaths = new List(); //LoadedAssemblies = new List(); //MethodDetailss = new List(); @@ -69,67 +69,67 @@ namespace Serein.NodeFlow /// /// 加载Dll /// - public event LoadDllHandler OnDllLoad; + public event LoadDllHandler? OnDllLoad; /// /// 移除DLL /// - public event RemoteDllHandler OnDllRemote; + public event RemoteDllHandler? OnDllRemote; /// /// 项目加载完成 /// - public event ProjectLoadedHandler OnProjectLoaded; + public event ProjectLoadedHandler? OnProjectLoaded; /// /// 节点连接属性改变事件 /// - public event NodeConnectChangeHandler OnNodeConnectChange; + public event NodeConnectChangeHandler? OnNodeConnectChange; /// /// 节点创建事件 /// - public event NodeCreateHandler OnNodeCreate; + public event NodeCreateHandler? OnNodeCreate; /// /// 移除节点事件 /// - public event NodeRemoteHandler OnNodeRemote; + public event NodeRemoteHandler? OnNodeRemote; /// /// 起始节点变化事件 /// - public event StartNodeChangeHandler OnStartNodeChange; + public event StartNodeChangeHandler? OnStartNodeChange; /// /// 流程运行完成事件 /// - public event FlowRunCompleteHandler OnFlowRunComplete; + public event FlowRunCompleteHandler? OnFlowRunComplete; /// /// 被监视的对象改变事件 /// - public event MonitorObjectChangeHandler OnMonitorObjectChange; + public event MonitorObjectChangeHandler? OnMonitorObjectChange; /// /// 节点中断状态改变事件 /// - public event NodeInterruptStateChangeHandler OnNodeInterruptStateChange; + public event NodeInterruptStateChangeHandler? OnNodeInterruptStateChange; /// /// 节点触发了中断 /// - public event ExpInterruptTriggerHandler OnInterruptTrigger; + public event ExpInterruptTriggerHandler? OnInterruptTrigger; /// /// 容器改变 /// - public event IOCMembersChangedHandler OnIOCMembersChanged; + public event IOCMembersChangedHandler? OnIOCMembersChanged; /// /// 节点需要定位 /// - public event NodeLocatedHandler OnNodeLocate; + public event NodeLocatedHandler? OnNodeLocate; #endregion #region 属性 @@ -196,12 +196,12 @@ namespace Serein.NodeFlow /// /// 起始节点私有属性 /// - private NodeModelBase _startNode; + private NodeModelBase? _startNode = null; /// /// 起始节点 /// - private NodeModelBase StartNode + private NodeModelBase? StartNode { get { @@ -209,6 +209,10 @@ namespace Serein.NodeFlow } set { + if (value is null) + { + return; + } if (_startNode is not null) { _startNode.IsStart = false; @@ -481,17 +485,19 @@ namespace Serein.NodeFlow public bool RemoteDll(string assemblyFullName) { - var library = NodeLibrarys.FirstOrDefault(nl => nl.Assembly.FullName.Equals(assemblyFullName)); + var library = NodeLibrarys.FirstOrDefault(nl => assemblyFullName.Equals(nl.Assembly.FullName)); if(library is null) { return false; } - - var nodes = Nodes.Values.ToDictionary( - key => key.MethodDetails.MethodName, - value => value - ); - if(nodes.Count == 0) + var groupedNodes = Nodes.Values + .Where(node => node.MethodDetails is not null) + .ToArray() + .GroupBy(node => node.MethodDetails!.MethodName) + .ToDictionary( + key => key.Key, + group => group.Count()); + if(Nodes.Count == 0) { return true; // 当前无节点,可以直接删除 } @@ -500,9 +506,12 @@ namespace Serein.NodeFlow { foreach(var md in mds) { - if (nodes.ContainsKey(md.MethodName)) + if(groupedNodes.TryGetValue(md.MethodName,out int count)) { - return false; // 创建过相关的节点 + if (count > 0) + { + return false; // 创建过相关的节点 + } } } MethodDetailss.Remove(library); @@ -510,7 +519,7 @@ namespace Serein.NodeFlow } else { - return true; + return true; } } @@ -685,9 +694,10 @@ namespace Serein.NodeFlow } } - public bool TryGetDelegate(string methodName, out Delegate del) + public bool TryGetDelegate(string methodName, out Delegate? del) { - if (MethodDelegates.TryGetValue(methodName, out del)) + + if (!string.IsNullOrEmpty(methodName) && MethodDelegates.TryGetValue(methodName, out del)) { return del != null; } @@ -742,7 +752,7 @@ namespace Serein.NodeFlow return false; } nodeModel.DebugSetting.InterruptClass = interruptClass; - OnNodeInterruptStateChange.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass)); + OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass)); return true; } @@ -958,11 +968,19 @@ namespace Serein.NodeFlow { // 加载DLL,创建 MethodDetails、实例作用对象、委托方法 var assemblyName = type.Assembly.GetName().Name; + if (string.IsNullOrEmpty(assemblyName)) + { + continue; + } var methods = MethodDetailsHelperTmp.GetMethodsToProcess(type); foreach(var method in methods) { (var md, var del) = MethodDetailsHelperTmp.CreateMethodDetails(type, method, assemblyName); - + if(md is null || del is null) + { + Console.WriteLine($"无法加载方法信息:{assemblyName}-{type}-{method}"); + continue; + } if (MethodDelegates.TryAdd(md.MethodName, del)) { methodDetails.Add(md); diff --git a/NodeFlow/Model/CompositeActionNode.cs b/NodeFlow/Model/CompositeActionNode.cs index e51f7a5..022ee78 100644 --- a/NodeFlow/Model/CompositeActionNode.cs +++ b/NodeFlow/Model/CompositeActionNode.cs @@ -30,7 +30,7 @@ namespace Serein.NodeFlow.Model { return []; } - internal override NodeInfo ToInfo() + internal override NodeInfo? ToInfo() { if (MethodDetails is null) return null; diff --git a/NodeFlow/Tool/MethodDetailsHelper.cs b/NodeFlow/Tool/MethodDetailsHelper.cs index 632ed1e..28b4610 100644 --- a/NodeFlow/Tool/MethodDetailsHelper.cs +++ b/NodeFlow/Tool/MethodDetailsHelper.cs @@ -52,7 +52,7 @@ public static class MethodDetailsHelperTmp /// 创建方法信息 /// /// - public static (MethodDetails,Delegate) CreateMethodDetails(Type type, MethodInfo method, string assemblyName) + public static (MethodDetails?,Delegate?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName) { var methodName = method.Name; diff --git a/NodeFlow/Tool/ObjDynamicCreateHelper.cs b/NodeFlow/Tool/ObjDynamicCreateHelper.cs index a30fcf2..d269cf0 100644 --- a/NodeFlow/Tool/ObjDynamicCreateHelper.cs +++ b/NodeFlow/Tool/ObjDynamicCreateHelper.cs @@ -1,13 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Emit; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System; -using System.Collections.Generic; -using System.Reflection; +using System.Reflection; using System.Reflection.Emit; @@ -78,7 +69,7 @@ namespace Serein.NodeFlow.Tool // 如果类型已经缓存,直接返回缓存的类型 if (typeCache.ContainsKey(typeName)) { - return Activator.CreateInstance(typeCache[typeName]); + return Activator.CreateInstance(typeCache[typeName])!; } // 定义动态程序集和模块 @@ -98,7 +89,7 @@ namespace Serein.NodeFlow.Tool if (propValue is IList>) // 处理数组类型 { - var nestedPropValue = (propValue as IList>)[0]; + var nestedPropValue = (propValue as IList>)![0]; var nestedType = CreateObjectWithProperties(nestedPropValue, $"{propName}Element"); propType = nestedType.GetType().MakeArrayType(); // 创建数组类型 } @@ -152,7 +143,7 @@ namespace Serein.NodeFlow.Tool typeCache[typeName] = dynamicType; // 创建对象实例 - return Activator.CreateInstance(dynamicType); + return Activator.CreateInstance(dynamicType)!; } // 方法 2: 递归设置对象的属性值 @@ -169,10 +160,10 @@ namespace Serein.NodeFlow.Tool if (value is Dictionary nestedProperties) { // 创建嵌套对象 - var nestedObj = Activator.CreateInstance(propInfo.PropertyType); + var nestedObj = Activator.CreateInstance(propInfo!.PropertyType); // 递归设置嵌套对象的值 - SetPropertyValues(nestedObj, nestedProperties); + SetPropertyValues(nestedObj!, nestedProperties); // 将嵌套对象赋值给属性 propInfo.SetValue(obj, nestedObj); @@ -180,7 +171,7 @@ namespace Serein.NodeFlow.Tool else { // 直接赋值给属性 - propInfo.SetValue(obj, value); + propInfo!.SetValue(obj, value); } } } @@ -222,7 +213,7 @@ namespace Serein.NodeFlow.Tool if (propValue is Dictionary nestedProperties) { var nestedObj = Activator.CreateInstance(propInfo.PropertyType); - if (SetPropertyValuesWithValidation(nestedObj, nestedProperties)) + if (nestedObj is not null && SetPropertyValuesWithValidation(nestedObj, nestedProperties)) { propInfo.SetValue(obj, nestedObj); } @@ -235,22 +226,24 @@ namespace Serein.NodeFlow.Tool { // 获取目标类型的数组元素类型 var elementType = propInfo.PropertyType.GetElementType(); - var array = Array.CreateInstance(elementType, list.Count); - - for (int i = 0; i < list.Count; i++) + if (elementType is not null) { - var item = Activator.CreateInstance(elementType); - if (SetPropertyValuesWithValidation(item, list[i])) - { - array.SetValue(item, i); - } - else - { - allSuccessful = false; // 赋值失败 - } - } + var array = Array.CreateInstance(elementType, list.Count); - propInfo.SetValue(obj, array); + for (int i = 0; i < list.Count; i++) + { + var item = Activator.CreateInstance(elementType); + if (item is not null && SetPropertyValuesWithValidation(item, list[i])) + { + array.SetValue(item, i); + } + else + { + allSuccessful = false; // 赋值失败 + } + } + propInfo.SetValue(obj, array); + } } else { diff --git a/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs b/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs index 71e7ce1..ef9493f 100644 --- a/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs +++ b/NodeFlow/Tool/SereinExpression/Resolver/MemberStringConditionResolver.cs @@ -39,7 +39,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression.Resolver return false; } - private object GetMemberValue(object? obj, string memberPath) + private object? GetMemberValue(object? obj, string memberPath) { string[] members = memberPath[1..].Split('.'); foreach (var member in members) diff --git a/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs b/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs index f5008e4..7b6ccab 100644 --- a/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs +++ b/NodeFlow/Tool/SereinExpression/SereinConditionParser.cs @@ -29,7 +29,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression } } - public static SereinConditionResolver ConditionParse(object data, string expression) + public static SereinConditionResolver ConditionParse(object? data, string expression) { if (expression.StartsWith('.') || expression.StartsWith('<')) // 表达式前缀属于从上一个节点数据对象获取成员值 { @@ -91,7 +91,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression /// /// 解析对象表达式 /// - private static SereinConditionResolver ParseObjectExpression(object data, string expression) + private static SereinConditionResolver ParseObjectExpression(object? data, string expression) { var parts = expression.Split(' '); string operatorStr = parts[0]; // 获取操作类型 diff --git a/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs b/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs index 9125247..03d0d64 100644 --- a/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs +++ b/NodeFlow/Tool/SereinExpression/SerinExpressionEvaluator.cs @@ -41,7 +41,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression /// /// /// - public static object Evaluate(string expression, object targetObJ, out bool isChange) + public static object? Evaluate(string expression, object targetObJ, out bool isChange) { var parts = expression.Split([' '], 2); if (parts.Length != 2) @@ -84,7 +84,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression /// 方法名称 /// /// - private static object InvokeMethod(object target, string methodCall) + private static object? InvokeMethod(object target, string methodCall) { var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries); if (methodParts.Length != 2) @@ -98,12 +98,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression .Select(p => p.Trim()) .ToArray(); - var method = target.GetType().GetMethod(methodName); - if (method is null) - { - throw new ArgumentException($"Method {methodName} not found on target."); - } - + var method = target.GetType().GetMethod(methodName) ?? throw new ArgumentException($"Method {methodName} not found on target."); var parameterValues = method.GetParameters() .Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType)) .ToArray(); @@ -119,15 +114,14 @@ namespace Serein.NodeFlow.Tool.SereinExpression /// 属性路径 /// /// - private static object GetMember(object target, string memberPath) + private static object? GetMember(object? target, string memberPath) { + if (target is null) return null; // 分割成员路径,按 '.' 处理多级访问 var members = memberPath.Split('.'); foreach (var member in members) { - if (target == null) return null; - // 检查成员是否包含数组索引,例如 "cars[0]" var arrayIndexStart = member.IndexOf('['); if (arrayIndexStart != -1) @@ -148,22 +142,22 @@ namespace Serein.NodeFlow.Tool.SereinExpression } // 获取数组或集合对象 - var arrayProperty = target.GetType().GetProperty(arrayName); - if (arrayProperty != null) + var arrayProperty = target?.GetType().GetProperty(arrayName); + if (arrayProperty is null) { - target = arrayProperty.GetValue(target); - } - else - { - var arrayField = target.GetType().GetField(arrayName); - if (arrayField != null) - { - target = arrayField.GetValue(target); - } - else + var arrayField = target?.GetType().GetField(arrayName); + if (arrayField is null) { throw new ArgumentException($"Member {arrayName} not found on target."); } + else + { + target = arrayField.GetValue(target); + } + } + else + { + target = arrayProperty.GetValue(target); } // 访问数组或集合中的指定索引 @@ -191,22 +185,22 @@ namespace Serein.NodeFlow.Tool.SereinExpression else { // 处理非数组情况的属性或字段 - var property = target.GetType().GetProperty(member); - if (property != null) + var property = target?.GetType().GetProperty(member); + if (property is null) { - target = property.GetValue(target); - } - else - { - var field = target.GetType().GetField(member); - if (field != null) - { - target = field.GetValue(target); - } - else + var field = target?.GetType().GetField(member); + if (field is null) { throw new ArgumentException($"Member {member} not found on target."); } + else + { + target = field.GetValue(target); + } + } + else + { + target = property.GetValue(target); } } } @@ -220,7 +214,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression /// 属性路径 /// /// - private static object SetMember(object target, string assignment) + private static object? SetMember(object? target, string assignment) { var parts = assignment.Split(new[] { '=' }, 2); if (parts.Length != 2) @@ -238,7 +232,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression // 检查是否包含数组索引 var arrayIndexStart = member.IndexOf('['); - if (arrayIndexStart != -1) + if (arrayIndexStart != -1) { // 解析数组名和索引 var arrayName = member.Substring(0, arrayIndexStart); @@ -255,24 +249,24 @@ namespace Serein.NodeFlow.Tool.SereinExpression } // 获取数组或集合 - var arrayProperty = target.GetType().GetProperty(arrayName); - if (arrayProperty != null) + var arrayProperty = target?.GetType().GetProperty(arrayName); + if (arrayProperty is null) { - target = arrayProperty.GetValue(target); - } - else - { - var arrayField = target.GetType().GetField(arrayName); - if (arrayField != null) - { - target = arrayField.GetValue(target); - } - else + var arrayField = target?.GetType().GetField(arrayName); + if (arrayField is null) { throw new ArgumentException($"Member {arrayName} not found on target."); } + else + { + target = arrayField.GetValue(target); + } } + else + { + target = arrayProperty.GetValue(target); + } // 获取目标数组或集合中的指定元素 if (target is Array array) @@ -299,46 +293,47 @@ namespace Serein.NodeFlow.Tool.SereinExpression else { // 处理非数组情况的属性或字段 - var property = target.GetType().GetProperty(member); - if (property != null) + var property = target?.GetType().GetProperty(member); + if (property is null) { - target = property.GetValue(target); - } - else - { - var field = target.GetType().GetField(member); - if (field != null) - { - target = field.GetValue(target); - } - else + var field = target?.GetType().GetField(member); + if (field is null) { throw new ArgumentException($"Member {member} not found on target."); } + else + { + target = field.GetValue(target); + } + } + else + { + target = property.GetValue(target); } } } + // 设置值 var lastMember = members.Last(); - var lastProperty = target.GetType().GetProperty(lastMember); - if (lastProperty != null) + var lastProperty = target?.GetType().GetProperty(lastMember); + if (lastProperty is null) { - var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType); - lastProperty.SetValue(target, convertedValue); - } - else - { - var lastField = target.GetType().GetField(lastMember); - if (lastField != null) + var lastField = target?.GetType().GetField(lastMember); + if (lastField is null) + { + throw new ArgumentException($"Member {lastMember} not found on target."); + } + else { var convertedValue = Convert.ChangeType(value, lastField.FieldType); lastField.SetValue(target, convertedValue); } - else - { - throw new ArgumentException($"Member {lastMember} not found on target."); - } + } + else + { + var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType); + lastProperty.SetValue(target, convertedValue); } return target; diff --git a/SereinFlow.sln b/SereinFlow.sln index e4e50da..4fe2841 100644 --- a/SereinFlow.sln +++ b/SereinFlow.sln @@ -18,7 +18,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serein.Library.Framework", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serein.Library", "Library\Serein.Library.csproj", "{5E19D0F2-913A-4D1C-A6F8-1E1227BAA0E3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Net461DllTest", "Net461DllTest\Net461DllTest.csproj", "{E40EE629-1A38-4011-88E3-9AD036869987}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Net462DllTest", "Net462DllTest\Net462DllTest.csproj", "{E40EE629-1A38-4011-88E3-9AD036869987}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/WorkBench/App.xaml.cs b/WorkBench/App.xaml.cs index 189ed28..63eaad1 100644 --- a/WorkBench/App.xaml.cs +++ b/WorkBench/App.xaml.cs @@ -12,24 +12,24 @@ namespace Serein.WorkBench /// public partial class App : Application { - public class TestObject - { + //public class TestObject + //{ - public NestedObject Data { get; set; } + // public NestedObject Data { get; set; } - public class NestedObject - { - public int Code { get; set; } - public int Code2 { get; set; } + // public class NestedObject + // { + // public int Code { get; set; } + // public int Code2 { get; set; } - public string Tips { get; set; } + // public string Tips { get; set; } - } - public string ToUpper(string input) - { - return input.ToUpper(); - } - } + // } + // public string ToUpper(string input) + // { + // return input.ToUpper(); + // } + //} @@ -125,7 +125,7 @@ namespace Serein.WorkBench /// 成功加载的工程文件 /// public static SereinProjectData? FlowProjectData { get; set; } - public static string FileDataPath = ""; + public static string FileDataPath { get; set; } = ""; private void Application_Startup(object sender, StartupEventArgs e) { // 检查是否传入了参数 @@ -163,7 +163,7 @@ namespace Serein.WorkBench string filePath; //filePath = @"F:\临时\project\tmp\project.dnf"; //filePath = @"D:\Project\C#\TestNetFramework\Net45DllTest\Net45DllTest\bin\Debug\project.dnf"; - filePath = @"D:\Project\C#\DynamicControl\SereinFlow\Net461DllTest\bin\Debug\project.dnf"; + filePath = @"D:\Project\C#\DynamicControl\SereinFlow\Net462DllTest\bin\Debug\project.dnf"; //string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf"; string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容 App.FlowProjectData = JsonConvert.DeserializeObject(content); diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs index 5d4dccb..66a623b 100644 --- a/WorkBench/MainWindow.xaml.cs +++ b/WorkBench/MainWindow.xaml.cs @@ -139,15 +139,15 @@ namespace Serein.WorkBench /// /// 组合变换容器 /// - private TransformGroup canvasTransformGroup; + private readonly TransformGroup canvasTransformGroup; /// /// 缩放画布 /// - private ScaleTransform scaleTransform; + private readonly ScaleTransform scaleTransform; /// /// 平移画布 /// - private TranslateTransform translateTransform; + private readonly TranslateTransform translateTransform; #endregion public MainWindow() @@ -162,10 +162,17 @@ namespace Serein.WorkBench InitFlowEnvironmentEvent(); // 配置环境事件 logWindow = InitConsoleOut(); // 重定向 Console 输出 - InitCanvasUI(); // 配置画布 + canvasTransformGroup = new TransformGroup(); + scaleTransform = new ScaleTransform(); + translateTransform = new TranslateTransform(); + + canvasTransformGroup.Children.Add(scaleTransform); + canvasTransformGroup.Children.Add(translateTransform); + + FlowChartCanvas.RenderTransform = canvasTransformGroup; - if(App.FlowProjectData is not null) + if (App.FlowProjectData is not null) { FlowEnvironment.LoadProject(App.FlowProjectData, App.FileDataPath); // 加载项目 } @@ -198,17 +205,7 @@ namespace Serein.WorkBench - private void InitCanvasUI() - { - canvasTransformGroup = new TransformGroup(); - scaleTransform = new ScaleTransform(); - translateTransform = new TranslateTransform(); - - canvasTransformGroup.Children.Add(scaleTransform); - canvasTransformGroup.Children.Add(translateTransform); - FlowChartCanvas.RenderTransform = canvasTransformGroup; - } private LogWindow InitConsoleOut() { @@ -243,7 +240,7 @@ namespace Serein.WorkBench } var canvasData = project.Basic.Canvas; - if (canvasData != null) + if (canvasData is not null) { scaleTransform.ScaleX = 1; scaleTransform.ScaleY = 1; @@ -355,9 +352,9 @@ namespace Serein.WorkBench End = toNode, Type = connectionType }; - if (toNode is FlipflopNodeControl flipflopControl) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器 + if (toNode is FlipflopNodeControl flipflopControl + && flipflopControl?.ViewModel?.Node is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器 { - var nodeModel = flipflopControl?.ViewModel?.Node; NodeTreeViewer.RemoteGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除 } @@ -556,7 +553,7 @@ namespace Serein.WorkBench } else { - if (ViewObjectViewer.MonitorKey.Equals(monitorKey)) // 相同对象 + if (monitorKey.Equals(ViewObjectViewer.MonitorKey)) // 相同对象 { ViewObjectViewer.RefreshObjectTree(eventArgs.NewData); // 刷新 } @@ -704,7 +701,7 @@ namespace Serein.WorkBench /// 抖动第一下偏移量 /// 减弱幅度(小于等于power,大于0) /// 持续系数(大于0),越大时间越长, - private static void ElasticAnimation(NodeControlBase? nodeControl, TranslateTransform translate, int power, int range = 1, double speed = 1) + private static void ElasticAnimation(NodeControlBase nodeControl, TranslateTransform translate, int power, int range = 1, double speed = 1) { DoubleAnimationUsingKeyFrames animation1 = new DoubleAnimationUsingKeyFrames(); for (int i = power, j = 1; i >= 0; i -= range) @@ -883,10 +880,10 @@ namespace Serein.WorkBench /// 任何情景下都尽量避免直接操作 ViewModel 中的 NodeModel 节点,而是应该调用 FlowEnvironment 提供接口进行操作。 因为 Workbench 应该更加关注UI视觉效果,而非直接干扰流程环境运行的逻辑。 之所以暴露 NodeModel 属性,因为有些场景下不可避免的需要直接获取节点的属性。 private void ConfigureContextMenu(NodeControlBase nodeControl) { + var contextMenu = new ContextMenu(); - // var nodeModel = nodeControl.ViewModel.Node; - + if (nodeControl.ViewModel.Node?.MethodDetails?.ReturnType is Type returnType && returnType != typeof(void)) { contextMenu.Items.Add(CreateMenuItem("查看返回类型", (s, e) => @@ -894,7 +891,7 @@ namespace Serein.WorkBench DisplayReturnTypeTreeViewer(returnType); })); } - var nodeGuid = nodeControl?.ViewModel?.Node?.Guid; + var nodeGuid = nodeControl.ViewModel?.Node?.Guid; #region 右键菜单功能 - 中断 @@ -923,10 +920,10 @@ namespace Serein.WorkBench contextMenu.Items.Add(CreateMenuItem("设为起点", (s, e) => FlowEnvironment.SetStartNode(nodeGuid))); contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => FlowEnvironment.RemoteNode(nodeGuid))); - contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsSucceed))); - contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsFail))); - contextMenu.Items.Add(CreateMenuItem("添加 异常分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsError))); - contextMenu.Items.Add(CreateMenuItem("添加 上游分支", (s, e) => StartConnection(nodeControl, ConnectionType.Upstream))); + contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection((NodeControlBase)s, ConnectionType.IsSucceed))); + contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection((NodeControlBase)s, ConnectionType.IsFail))); + contextMenu.Items.Add(CreateMenuItem("添加 异常分支", (s, e) => StartConnection((NodeControlBase)s, ConnectionType.IsError))); + contextMenu.Items.Add(CreateMenuItem("添加 上游分支", (s, e) => StartConnection((NodeControlBase)s, ConnectionType.Upstream))); @@ -976,6 +973,10 @@ namespace Serein.WorkBench { var contextMenu = new ContextMenu(); contextMenu.Items.Add(CreateMenuItem("删除连线", (s, e) => DeleteConnection(connection))); + if (connection.ArrowPath is null || connection.BezierPath is null) + { + return; + } connection.ArrowPath.ContextMenu = contextMenu; connection.BezierPath.ContextMenu = contextMenu; } @@ -1198,8 +1199,8 @@ namespace Serein.WorkBench // 准备放置条件表达式控件 if (nodeControl.ViewModel.Node.ControlType == NodeControlType.ExpCondition) { - ConditionRegionControl conditionRegion = GetParentOfType(hitElement); - if (conditionRegion != null) + ConditionRegionControl? conditionRegion = GetParentOfType(hitElement); + if (conditionRegion is not null) { TryPlaceNodeInRegion(conditionRegion, nodeControl); //// 如果存在条件区域容器 @@ -1222,8 +1223,8 @@ namespace Serein.WorkBench // 准备放置条件表达式控件 if (nodeControl.ViewModel.Node.ControlType == NodeControlType.ExpCondition) { - ConditionRegionControl conditionRegion = regionControl as ConditionRegionControl; - if (conditionRegion != null) + ConditionRegionControl? conditionRegion = regionControl as ConditionRegionControl; + if (conditionRegion is not null) { // 如果存在条件区域容器 conditionRegion.AddCondition(nodeControl); @@ -1365,14 +1366,17 @@ namespace Serein.WorkBench } private void ChangeViewerObjOfNode(NodeControlBase nodeControl) { - var node = nodeControl?.ViewModel?.Node; + var node = nodeControl.ViewModel.Node; //if (node is not null && (node.MethodDetails is null || node.MethodDetails.ReturnType != typeof(void)) - if (node is not null && node?.MethodDetails?.ReturnType != typeof(void)) + 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); + if(instance is not null) + { + ViewObjectViewer.LoadObjectInformation(key, instance); + ChangeViewerObj(key, instance); + } } } public void ChangeViewerObj(string key, object instance) @@ -1768,64 +1772,6 @@ namespace Serein.WorkBench } e.Handled = true; // 防止事件传播影响其他控件 - return; - // 如果正在选取状态,再次点击画布时自动确定选取范围,否则进入选取状态 - if (IsSelectControl) - { - IsSelectControl = false; - // 释放鼠标捕获 - FlowChartCanvas.ReleaseMouseCapture(); - - // 隐藏选取矩形(如果需要保持选取状态显示,可以删除此行) - SelectionRectangle.Visibility = Visibility.Collapsed; - - // 处理选取区域内的元素(例如,获取选取范围内的控件) - Rect selectionArea = new Rect(Canvas.GetLeft(SelectionRectangle), - Canvas.GetTop(SelectionRectangle), - SelectionRectangle.Width, - SelectionRectangle.Height); - - - // 在此处处理选取的逻辑 - foreach (UIElement element in FlowChartCanvas.Children) - { - Rect elementBounds = new Rect(Canvas.GetLeft(element), Canvas.GetTop(element), - element.RenderSize.Width, element.RenderSize.Height); - - if (selectionArea.Contains(elementBounds)) - { - // 选中元素,执行相应操作 - if (element is NodeControlBase control) - { - selectNodeControls.Add(control); - } - } - } - SelectedNode();// 选择之后需要执行的操作 - } - else - { - // 进入选取状态 - IsSelectControl = true; - - // 开始选取时,记录鼠标起始点 - startSelectControolPoint = e.GetPosition(FlowChartCanvas); - - // 初始化选取矩形的位置和大小 - Canvas.SetLeft(SelectionRectangle, startSelectControolPoint.X); - Canvas.SetTop(SelectionRectangle, startSelectControolPoint.Y); - SelectionRectangle.Width = 0; - SelectionRectangle.Height = 0; - - // 显示选取矩形 - SelectionRectangle.Visibility = Visibility.Visible; - SelectionRectangle.ContextMenu ??= ConfiguerSelectionRectangle(); - - // 捕获鼠标,以便在鼠标移动到Canvas外部时仍能处理事件 - FlowChartCanvas.CaptureMouse(); - - } - e.Handled = true; // 防止事件传播影响其他控件 } /// @@ -2323,13 +2269,13 @@ namespace Serein.WorkBench /// /// /// - private static T GetParentOfType(DependencyObject element) where T : DependencyObject + private static T? GetParentOfType(DependencyObject element) where T : DependencyObject { while (element != null) { - if (element is T) + if (element is T e) { - return element as T; + return e; } element = VisualTreeHelper.GetParent(element); } @@ -2342,9 +2288,9 @@ namespace Serein.WorkBench private void JudgmentFlipFlopNode(NodeControlBase nodeControl) { - if (nodeControl is FlipflopNodeControl flipflopControl) // 判断是否为触发器 + if (nodeControl is FlipflopNodeControl flipflopControl + && flipflopControl?.ViewModel?.Node is NodeModelBase nodeModel) // 判断是否为触发器 { - var nodeModel = flipflopControl?.ViewModel?.Node; int count = 0; foreach (var ct in NodeStaticConfig.ConnectionTypes) { @@ -2473,13 +2419,18 @@ namespace Serein.WorkBench node.Position = new Position(positionRelativeToParent.X, positionRelativeToParent.Y); } } - var isPass = SaveContentToFile(out string savePath, out Action? savaProjectFile); - if(!isPass) + if (!SaveContentToFile(out string savePath, out Action? savaProjectFile)) { + Console.WriteLine("保存项目DLL时返回了意外的文件保存路径"); return; } - string librarySavePath = System.IO.Path.GetDirectoryName(savePath); + string? librarySavePath = System.IO.Path.GetDirectoryName(savePath); + if (string.IsNullOrEmpty(librarySavePath)) + { + Console.WriteLine("保存项目DLL时返回了意外的文件保存路径"); + return; + } Console.WriteLine(savePath); for (int index = 0; index < projectData.Librarys.Length; index++) { @@ -2578,17 +2529,17 @@ namespace Serein.WorkBench /// private void ButtonTestExpObj_Click(object sender, RoutedEventArgs e) { - string jsonString = - """ - { - "Name": "张三", - "Age": 24, - "Address": { - "City": "北京", - "PostalCode": "10000" - } - } - """; + //string jsonString = + //""" + //{ + // "Name": "张三", + // "Age": 24, + // "Address": { + // "City": "北京", + // "PostalCode": "10000" + // } + //} + //"""; var externalData = new Dictionary { @@ -2615,12 +2566,12 @@ namespace Serein.WorkBench Console.WriteLine("赋值过程中有错误,请检查属性名和类型!"); } - ObjDynamicCreateHelper.PrintObjectProperties(result); + ObjDynamicCreateHelper.PrintObjectProperties(result!); Console.WriteLine( ); var exp = "@set .Addresses[1].Street = qwq"; - var data = SerinExpressionEvaluator.Evaluate(exp, result, out bool isChange); + var data = SerinExpressionEvaluator.Evaluate(exp, result!, out bool isChange); exp = "@get .Addresses[1].Street"; - data = SerinExpressionEvaluator.Evaluate(exp,result, out isChange); + data = SerinExpressionEvaluator.Evaluate(exp,result!, out isChange); Console.WriteLine($"{exp} => {data}"); } @@ -2681,22 +2632,29 @@ namespace Serein.WorkBench canvas.Dispatcher.InvokeAsync(() => { - if (connection is not null && connection.BezierPath is null) + if (connection is null) + { + return; + } + + if (connection.BezierPath is null) { connection.BezierPath = new System.Windows.Shapes.Path { Stroke = BezierLineDrawer.GetLineColor(connection.Type), StrokeThickness = 1 }; //Canvas.SetZIndex(connection.BezierPath, -1); canvas.Children.Add(connection.BezierPath); } - if (connection is not null && connection.ArrowPath is null) + if (connection.ArrowPath is null) { connection.ArrowPath = new System.Windows.Shapes.Path { Stroke = BezierLineDrawer.GetLineColor(connection.Type), Fill = BezierLineDrawer.GetLineColor(connection.Type), StrokeThickness = 1 }; //Canvas.SetZIndex(connection.ArrowPath, -1); canvas.Children.Add(connection.ArrowPath); } + BezierLineDrawer.UpdateBezierLine(canvas, connection.Start, connection.End, connection.BezierPath, connection.ArrowPath); isUpdating = false; + }); } @@ -2746,10 +2704,10 @@ namespace Serein.WorkBench public class Connection { public ConnectionType Type { get; set; } - public Canvas Canvas { get; set; }// 贝塞尔曲线所在画布 + public Canvas? Canvas { get; set; }// 贝塞尔曲线所在画布 - public System.Windows.Shapes.Path BezierPath { get; set; }// 贝塞尔曲线路径 - public System.Windows.Shapes.Path ArrowPath { get; set; } // 箭头路径 + public System.Windows.Shapes.Path? BezierPath { get; set; }// 贝塞尔曲线路径 + public System.Windows.Shapes.Path? ArrowPath { get; set; } // 箭头路径 public required NodeControlBase Start { get; set; } // 起始 public required NodeControlBase End { get; set; } // 结束 @@ -2757,8 +2715,11 @@ namespace Serein.WorkBench public void RemoveFromCanvas() { - Canvas.Children.Remove(BezierPath); // 移除线 - Canvas.Children.Remove(ArrowPath); // 移除线 + if(Canvas != null) + { + Canvas.Children.Remove(BezierPath); // 移除线 + Canvas.Children.Remove(ArrowPath); // 移除线 + } } /// @@ -2766,6 +2727,10 @@ namespace Serein.WorkBench /// public void Refresh() { + if(Canvas is null || BezierPath is null || ArrowPath is null) + { + return; + } BezierLineDrawer.UpdateBezierLine(Canvas, Start, End, BezierPath, ArrowPath); } } diff --git a/WorkBench/Node/View/ConditionRegionControl.xaml.cs b/WorkBench/Node/View/ConditionRegionControl.xaml.cs index 80339e7..e1a650a 100644 --- a/WorkBench/Node/View/ConditionRegionControl.xaml.cs +++ b/WorkBench/Node/View/ConditionRegionControl.xaml.cs @@ -12,7 +12,6 @@ namespace Serein.WorkBench.Node.View /// public partial class ConditionRegionControl : NodeControlBase { - private Point _dragStartPoint; public ConditionRegionControl() : base() { diff --git a/WorkBench/Themes/NodeTreeItemViewControl.xaml.cs b/WorkBench/Themes/NodeTreeItemViewControl.xaml.cs index d5b5a9e..c35edad 100644 --- a/WorkBench/Themes/NodeTreeItemViewControl.xaml.cs +++ b/WorkBench/Themes/NodeTreeItemViewControl.xaml.cs @@ -74,7 +74,7 @@ namespace Serein.WorkBench.Themes {ConnectionType.IsError, []}, } }; - string itemName = rootNodeModel?.MethodDetails?.MethodTips; + string? itemName = rootNodeModel.MethodDetails?.MethodTips; if (string.IsNullOrEmpty(itemName)) { itemName = rootNodeModel.ControlType.ToString(); @@ -141,10 +141,10 @@ namespace Serein.WorkBench.Themes RootNode = child, ChildNodes = child.SuccessorNodes, }; - string itemName = child?.MethodDetails?.MethodTips; + string? itemName = child?.MethodDetails?.MethodTips; if (string.IsNullOrEmpty(itemName)) { - itemName = child.ControlType.ToString(); + itemName = child?.ControlType.ToString(); } TreeViewItem treeViewItem = new TreeViewItem { @@ -204,10 +204,10 @@ namespace Serein.WorkBench.Themes ChildNodes = childNodeModel.SuccessorNodes, }; - string itemName = childNodeModel?.MethodDetails?.MethodTips; + string? itemName = childNodeModel?.MethodDetails?.MethodTips; if (string.IsNullOrEmpty(itemName)) { - itemName = childNodeModel.ControlType.ToString(); + itemName = childNodeModel?.ControlType.ToString(); } TreeViewItem treeViewItem = new TreeViewItem { diff --git a/WorkBench/Themes/NodeTreeViewControl.xaml.cs b/WorkBench/Themes/NodeTreeViewControl.xaml.cs index 70f4a0e..39c7cb6 100644 --- a/WorkBench/Themes/NodeTreeViewControl.xaml.cs +++ b/WorkBench/Themes/NodeTreeViewControl.xaml.cs @@ -22,7 +22,6 @@ namespace Serein.WorkBench.Themes /// public partial class NodeTreeViewControl : UserControl { - private IFlowEnvironment FlowEnvironment { get; set; } public NodeTreeViewControl() { InitializeComponent(); diff --git a/WorkBench/Themes/ObjectViewerControl.xaml.cs b/WorkBench/Themes/ObjectViewerControl.xaml.cs index 65390a2..cb292d4 100644 --- a/WorkBench/Themes/ObjectViewerControl.xaml.cs +++ b/WorkBench/Themes/ObjectViewerControl.xaml.cs @@ -32,7 +32,7 @@ namespace Serein.WorkBench.Themes /// /// 属性名称 /// - public string Name { get; set; } + public string? Name { get; set; } /// /// 属性类型 /// @@ -40,15 +40,15 @@ namespace Serein.WorkBench.Themes /// /// 数据类型 /// - public Type DataType { get; set; } + public Type? DataType { get; set; } /// /// 数据 /// - public object DataValue { get; set; } + public object? DataValue { get; set; } /// /// 数据路径 /// - public string DataPath { get; set; } + public string DataPath { get; set; } = string.Empty; } @@ -80,24 +80,24 @@ namespace Serein.WorkBench.Themes /// /// 运行环境 /// - public IFlowEnvironment FlowEnvironment { get; set; } + public IFlowEnvironment? FlowEnvironment { get; set; } /// /// 监视对象的键 /// - public string MonitorKey { get => monitorKey; } + public string? MonitorKey { get => monitorKey; } /// /// 正在监视的对象 /// - public object MonitorObj { get => monitorObj; } + public object? MonitorObj { get => monitorObj; } /// /// 监视表达式 /// - public string MonitorExpression { get => ExpressionTextBox.Text.ToString(); } + public string? MonitorExpression { get => ExpressionTextBox.Text.ToString(); } - private string monitorKey; - private object monitorObj; + private string? monitorKey; + private object? monitorObj; // 用于存储当前展开的节点路径 private HashSet expandedNodePaths = new HashSet(); @@ -133,7 +133,7 @@ namespace Serein.WorkBench.Themes /// private void UpMonitorExpressionButton_Click(object sender, RoutedEventArgs e) { - if (FlowEnvironment.AddInterruptExpression(monitorKey, MonitorExpression)) // 对象预览器尝试添加中断表达式 + if (FlowEnvironment is not null && FlowEnvironment.AddInterruptExpression(monitorKey, MonitorExpression)) // 对象预览器尝试添加中断表达式 { if (string.IsNullOrEmpty(MonitorExpression)) { @@ -146,7 +146,7 @@ namespace Serein.WorkBench.Themes } } - private TreeViewItem? LoadTree(object obj) + private TreeViewItem? LoadTree(object? obj) { if (obj is null) return null; var objectType = obj.GetType(); @@ -178,7 +178,7 @@ namespace Serein.WorkBench.Themes /// /// 刷新对象属性树 /// - public void RefreshObjectTree(object obj) + public void RefreshObjectTree(object? obj) { monitorObj = obj; var rootNode = LoadTree(obj); @@ -222,14 +222,20 @@ namespace Serein.WorkBench.Themes { if (item.Tag is FlowDataDetails flowDataDetails) // FlowDataDetails flowDataDetails object obj { - if (flowDataDetails.ItemType == TreeItemType.Item || item.Items.Count == 0) + if (flowDataDetails.ItemType != TreeItemType.Item && item.Items.Count != 0) { - // 记录当前节点的路径 - var path = flowDataDetails.DataPath; - expandedNodePaths.Add(path); - AddMembersToTreeNode(item, flowDataDetails.DataValue, flowDataDetails.DataType); + return; } - + if(flowDataDetails.DataValue is null || flowDataDetails.DataType is null) + { + return; + } + + // 记录当前节点的路径 + var path = flowDataDetails.DataPath; + expandedNodePaths.Add(path); + AddMembersToTreeNode(item, flowDataDetails.DataValue, flowDataDetails.DataType); + } } } @@ -276,8 +282,8 @@ namespace Serein.WorkBench.Themes continue; } - TreeViewItem memberNode = ConfigureTreeViewItem(obj, member); // 根据对象成员生成节点对象 - if (memberNode != null) + TreeViewItem? memberNode = ConfigureTreeViewItem(obj, member); // 根据对象成员生成节点对象 + if (memberNode is not null) { treeViewNode.Items.Add(memberNode); // 添加到当前节点 @@ -305,7 +311,7 @@ namespace Serein.WorkBench.Themes /// /// /// - private TreeViewItem ConfigureTreeViewItem(object obj, MemberInfo member) + private TreeViewItem? ConfigureTreeViewItem(object obj, MemberInfo member) { if (obj == null) { @@ -353,7 +359,7 @@ namespace Serein.WorkBench.Themes else { TreeViewItem memberNode = new TreeViewItem { Header = member.Name }; - string propertyValue = GetPropertyValue(obj, property, out object value); + string propertyValue = GetPropertyValue(obj, property, out object? value); memberNode.Tag = new FlowDataDetails { ItemType = TreeItemType.Property, @@ -417,7 +423,7 @@ namespace Serein.WorkBench.Themes else { TreeViewItem memberNode = new TreeViewItem { Header = member.Name }; - string fieldValue = GetFieldValue(obj, field, out object value); + string fieldValue = GetFieldValue(obj, field, out object? value); memberNode.Tag = new FlowDataDetails { @@ -454,7 +460,7 @@ namespace Serein.WorkBench.Themes /// /// /// - private string GetPropertyValue(object obj, PropertyInfo property,out object value) + private string GetPropertyValue(object obj, PropertyInfo property,out object? value) { try { @@ -482,7 +488,7 @@ namespace Serein.WorkBench.Themes /// /// /// - private string GetFieldValue(object obj, FieldInfo field, out object value) + private string GetFieldValue(object obj, FieldInfo field, out object? value) { try { diff --git a/WorkBench/Themes/TypeViewerWindow.xaml.cs b/WorkBench/Themes/TypeViewerWindow.xaml.cs index ceb0fcf..f8e18c3 100644 --- a/WorkBench/Themes/TypeViewerWindow.xaml.cs +++ b/WorkBench/Themes/TypeViewerWindow.xaml.cs @@ -227,10 +227,10 @@ namespace Serein.WorkBench.Themes /// /// 目标节点 /// 父节点 - private TreeViewItem GetParentTreeViewItem(TreeViewItem node) + private TreeViewItem? GetParentTreeViewItem(TreeViewItem node) { DependencyObject parent = VisualTreeHelper.GetParent(node); - while (parent != null && !(parent is TreeViewItem)) + while (parent != null && parent is not TreeViewItem) { parent = VisualTreeHelper.GetParent(parent); } diff --git a/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs b/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs index 39b5d18..3f85c37 100644 --- a/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs +++ b/WorkBench/Tool/Converters/InvertableBooleanToVisibilityConverter.cs @@ -29,7 +29,7 @@ namespace Serein.WorkBench.Tool.Converters return boolValue ? Visibility.Visible : Visibility.Collapsed; } - public object ConvertBack(object value, Type targetType, + public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return null;