diff --git a/Library/SerinExpression/ConditionResolver.cs b/Library/SerinExpression/ConditionResolver.cs new file mode 100644 index 0000000..f95b47b --- /dev/null +++ b/Library/SerinExpression/ConditionResolver.cs @@ -0,0 +1,337 @@ +using System.Reflection; + +namespace Serein.Library.SerinExpression +{ + /// + /// 条件解析抽象类 + /// + public abstract class ConditionResolver + { + public abstract bool Evaluate(object obj); + } + + public class PassConditionResolver : ConditionResolver + { + public Operator Op { get; set; } + public override bool Evaluate(object obj) + { + return Op switch + { + Operator.Pass => true, + Operator.NotPass => false, + _ => throw new NotSupportedException("不支持的条件类型") + }; + } + + public enum Operator + { + Pass, + NotPass, + } + + } + + public class ValueTypeConditionResolver : ConditionResolver where T : struct, IComparable + { + public enum Operator + { + /// + /// 不进行任何操作 + /// + Node, + /// + /// 大于 + /// + GreaterThan, + /// + /// 小于 + /// + LessThan, + /// + /// 等于 + /// + Equal, + /// + /// 大于或等于 + /// + GreaterThanOrEqual, + /// + /// 小于或等于 + /// + LessThanOrEqual, + /// + /// 在两者之间 + /// + InRange, + /// + /// 不在两者之间 + /// + OutOfRange + } + + public Operator Op { get; set; } + public T Value { get; set; } + public T RangeStart { get; set; } + public T RangeEnd { get; set; } + + public string ArithmeticExpression { get; set; } + + + public override bool Evaluate(object obj) + { + if (obj is T typedObj) + { + double numericValue = Convert.ToDouble(typedObj); + if (!string.IsNullOrEmpty(ArithmeticExpression)) + { + numericValue = SerinArithmeticExpressionEvaluator.Evaluate(ArithmeticExpression, numericValue); + } + + T evaluatedValue = (T)Convert.ChangeType(numericValue, typeof(T)); + + return Op switch + { + Operator.GreaterThan => evaluatedValue.CompareTo(Value) > 0, + Operator.LessThan => evaluatedValue.CompareTo(Value) < 0, + Operator.Equal => evaluatedValue.CompareTo(Value) == 0, + Operator.GreaterThanOrEqual => evaluatedValue.CompareTo(Value) >= 0, + Operator.LessThanOrEqual => evaluatedValue.CompareTo(Value) <= 0, + Operator.InRange => evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0, + Operator.OutOfRange => evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0, + _ => throw new NotSupportedException("不支持的条件类型") + }; + /* switch (Op) + { + case Operator.GreaterThan: + return evaluatedValue.CompareTo(Value) > 0; + case Operator.LessThan: + return evaluatedValue.CompareTo(Value) < 0; + case Operator.Equal: + return evaluatedValue.CompareTo(Value) == 0; + case Operator.GreaterThanOrEqual: + return evaluatedValue.CompareTo(Value) >= 0; + case Operator.LessThanOrEqual: + return evaluatedValue.CompareTo(Value) <= 0; + case Operator.InRange: + return evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0; + case Operator.OutOfRange: + return evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0; + }*/ + } + return false; + } + } + + public class BoolConditionResolver : ConditionResolver + { + public enum Operator + { + /// + /// 是 + /// + Is + } + + public Operator Op { get; set; } + public bool Value { get; set; } + + public override bool Evaluate(object obj) + { + + if (obj is bool boolObj) + { + return boolObj == Value; + /*switch (Op) + { + case Operator.Is: + return boolObj == Value; + }*/ + } + return false; + } + } + + public class StringConditionResolver : ConditionResolver + { + public enum Operator + { + /// + /// 出现过 + /// + Contains, + /// + /// 没有出现过 + /// + DoesNotContain, + /// + /// 相等 + /// + Equal, + /// + /// 不相等 + /// + NotEqual, + /// + /// 起始字符串等于 + /// + StartsWith, + /// + /// 结束字符串等于 + /// + EndsWith + } + + public Operator Op { get; set; } + + public string Value { get; set; } + + + public override bool Evaluate(object obj) + { + if (obj is string strObj) + { + return Op switch + { + Operator.Contains => strObj.Contains(Value), + Operator.DoesNotContain => !strObj.Contains(Value), + Operator.Equal => strObj == Value, + Operator.NotEqual => strObj != Value, + Operator.StartsWith => strObj.StartsWith(Value), + Operator.EndsWith => strObj.EndsWith(Value), + _ => throw new NotSupportedException("不支持的条件类型"), + }; + + /* switch (Op) + { + case Operator.Contains: + return strObj.Contains(Value); + case Operator.DoesNotContain: + return !strObj.Contains(Value); + case Operator.Equal: + return strObj == Value; + case Operator.NotEqual: + return strObj != Value; + case Operator.StartsWith: + return strObj.StartsWith(Value); + case Operator.EndsWith: + return strObj.EndsWith(Value); + }*/ + } + return false; + } + } + public class MemberConditionResolver : ConditionResolver where T : struct, IComparable + { + //public string MemberPath { get; set; } + public ValueTypeConditionResolver.Operator Op { get; set; } + public object? TargetObj { get; set; } + public T Value { get; set; } + + public string ArithmeticExpression { get; set; } + + public override bool Evaluate(object? obj) + { + //object? memberValue = GetMemberValue(obj, MemberPath); + if (TargetObj is T typedObj) + { + return new ValueTypeConditionResolver + { + Op = Op, + Value = Value, + ArithmeticExpression = ArithmeticExpression, + }.Evaluate(typedObj); + } + return false; + } + + //private object? GetMemberValue(object? obj, string memberPath) + //{ + // string[] members = memberPath[1..].Split('.'); + // foreach (var member in members) + // { + // if (obj == null) return null; + // Type type = obj.GetType(); + // PropertyInfo? propertyInfo = type.GetProperty(member); + // FieldInfo? fieldInfo = type.GetField(member); + // if (propertyInfo != null) + // obj = propertyInfo.GetValue(obj); + // else if (fieldInfo != null) + // obj = fieldInfo.GetValue(obj); + // else + // throw new ArgumentException($"Member {member} not found in type {type.FullName}"); + // } + // return obj; + //} + } + + public class MemberStringConditionResolver : ConditionResolver + { + + public string MemberPath { get; set; } + + public StringConditionResolver.Operator Op { get; set; } + + public string Value { get; set; } + + + public override bool Evaluate(object obj) + { + object memberValue = GetMemberValue(obj, MemberPath); + if (memberValue is string strObj) + { + return new StringConditionResolver + { + Op = Op, + Value = Value + }.Evaluate(strObj); + } + return false; + } + + private object GetMemberValue(object? obj, string memberPath) + { + string[] members = memberPath[1..].Split('.'); + foreach (var member in members) + { + + if (obj == null) return null; + + Type type = obj.GetType(); + PropertyInfo? propertyInfo = type.GetProperty(member); + FieldInfo? fieldInfo = type.GetField(member); + if (propertyInfo != null) + obj = propertyInfo.GetValue(obj); + else if (fieldInfo != null) + obj = fieldInfo.GetValue(obj); + else + throw new ArgumentException($"Member {member} not found in type {type.FullName}"); + } + + return obj; + + } + + + + + + private static string GetArithmeticExpression(string part) + { + int startIndex = part.IndexOf('['); + int endIndex = part.IndexOf(']'); + if (startIndex >= 0 && endIndex > startIndex) + { + return part.Substring(startIndex + 1, endIndex - startIndex - 1); + } + + return null; + + } + + + + + + } + +} diff --git a/Library/SerinExpression/SerinConditionParser.cs b/Library/SerinExpression/SerinConditionParser.cs new file mode 100644 index 0000000..5b9348e --- /dev/null +++ b/Library/SerinExpression/SerinConditionParser.cs @@ -0,0 +1,337 @@ +using System.Globalization; +using System.Reflection; + +namespace Serein.Library.SerinExpression; + +public class SerinConditionParser +{ + public static bool To(T data, string expression) + { + try + { + + return ConditionParse(data, expression).Evaluate(data); + + } + catch (Exception ex) + { + Console.WriteLine(ex); + throw; + } + } + + public static ConditionResolver ConditionParse(object data, string expression) + { + if (expression.StartsWith('.')) // 表达式前缀属于从上一个节点数据对象获取成员值 + { + return ParseObjectExpression(data, expression); + } + else + { + return ParseSimpleExpression(data, expression); + } + + + //bool ContainsArithmeticOperators(string expression) + //{ + // return expression.Contains('+') || expression.Contains('-') || expression.Contains('*') || expression.Contains('/'); + //} + + } + + /// + /// 获取计算表达式的部分 + /// + /// + /// + private static string GetArithmeticExpression(string part) + { + int startIndex = part.IndexOf('['); + int endIndex = part.IndexOf(']'); + if (startIndex >= 0 && endIndex > startIndex) + { + return part.Substring(startIndex + 1, endIndex - startIndex - 1); + } + + return null; + + } + /// + /// 获取对象指定名称的成员 + /// + private static object? GetMemberValue(object? obj, string memberPath) + { + string[] members = memberPath[1..].Split('.'); + foreach (var member in members) + { + if (obj == null) return null; + Type type = obj.GetType(); + PropertyInfo? propertyInfo = type.GetProperty(member); + FieldInfo? fieldInfo = type.GetField(member); + if (propertyInfo != null) + obj = propertyInfo.GetValue(obj); + else if (fieldInfo != null) + obj = fieldInfo.GetValue(obj); + else + throw new ArgumentException($"Member {member} not found in type {type.FullName}"); + } + return obj; + } + /// + /// 解析对象表达式 + /// + private static ConditionResolver ParseObjectExpression(object data, string expression) + { + var parts = expression.Split(' '); + string operatorStr = parts[0]; + string valueStr = string.Join(' ', parts, 1, parts.Length - 1); + + int typeStartIndex = expression.IndexOf('<'); + int typeEndIndex = expression.IndexOf('>'); + + string memberPath; + Type type; + object? targetObj; + if (typeStartIndex + typeStartIndex == -2) + { + memberPath = operatorStr; + targetObj = GetMemberValue(data, operatorStr); + + type = targetObj.GetType(); + + operatorStr = parts[1].ToLower(); + valueStr = string.Join(' ', parts.Skip(2)); + } + else + { + if (typeStartIndex >= typeEndIndex) + { + throw new ArgumentException("无效的表达式格式"); + } + memberPath = expression.Substring(0, typeStartIndex).Trim(); + string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1).Trim().ToLower(); + parts = expression.Substring(typeEndIndex + 1).Trim().Split(' '); + if (parts.Length == 3) + { + operatorStr = parts[1].ToLower(); + valueStr = string.Join(' ', parts.Skip(2)); + } + else + { + operatorStr = parts[0].ToLower(); + valueStr = string.Join(' ', parts.Skip(1)); + } + targetObj = GetMemberValue(data, memberPath); + + Type? tempType = typeStr switch + { + "int" => typeof(int), + "double" => typeof(double), + "bool" => typeof(bool), + "string" => typeof(string), + _ => Type.GetType(typeStr) + }; + type = tempType ?? throw new ArgumentException("对象表达式无效的类型声明"); + } + + + + if (type == typeof(int)) + { + int value = int.Parse(valueStr, CultureInfo.InvariantCulture); + return new MemberConditionResolver + { + TargetObj = targetObj, + //MemberPath = memberPath, + Op = ParseValueTypeOperator(operatorStr), + Value = value, + ArithmeticExpression = GetArithmeticExpression(parts[0]) + }; + } + else if (type == typeof(double)) + { + double value = double.Parse(valueStr, CultureInfo.InvariantCulture); + return new MemberConditionResolver + { + //MemberPath = memberPath, + TargetObj = targetObj, + Op = ParseValueTypeOperator(operatorStr), + Value = value, + ArithmeticExpression = GetArithmeticExpression(parts[0]) + }; + + } + else if (type == typeof(bool)) + { + return new MemberConditionResolver + { + //MemberPath = memberPath, + TargetObj = targetObj, + Op = (ValueTypeConditionResolver.Operator)ParseBoolOperator(operatorStr) + }; + } + else if (type == typeof(string)) + { + return new MemberStringConditionResolver + { + MemberPath = memberPath, + Op = ParseStringOperator(operatorStr), + Value = valueStr + }; + } + + throw new NotSupportedException($"Type {type} is not supported."); + } + + private static ConditionResolver ParseSimpleExpression(object data, string expression) + { + if ("pass".Equals(expression.ToLower())) + { + return new PassConditionResolver + { + Op = PassConditionResolver.Operator.Pass, + }; + } + else + { + if ("not pass".Equals(expression.ToLower())) + { + return new PassConditionResolver + { + Op = PassConditionResolver.Operator.NotPass, + }; + } + if ("!pass".Equals(expression.ToLower())) + { + return new PassConditionResolver + { + Op = PassConditionResolver.Operator.NotPass, + }; + } + } + + + var parts = expression.Split(' '); + + if (parts.Length < 2) + throw new ArgumentException("无效的表达式格式。"); + + //string typeStr = parts[0]; + string operatorStr = parts[0]; + string valueStr = string.Join(' ', parts, 1, parts.Length - 1); + + Type type = data.GetType();//Type.GetType(typeStr); + if (type == typeof(int)) + { + var op = ParseValueTypeOperator(operatorStr); + if (op == ValueTypeConditionResolver.Operator.InRange || op == ValueTypeConditionResolver.Operator.OutOfRange) + { + var temp = valueStr.Split('-'); + if (temp.Length < 2) + throw new ArgumentException($"范围无效:{valueStr}。"); + int rangeStart = int.Parse(temp[0], CultureInfo.InvariantCulture); + int rangeEnd = int.Parse(temp[1], CultureInfo.InvariantCulture); + return new ValueTypeConditionResolver + { + Op = op, + RangeStart = rangeStart, + RangeEnd = rangeEnd, + ArithmeticExpression = GetArithmeticExpression(parts[0]), + }; + } + else + { + int value = int.Parse(valueStr, CultureInfo.InvariantCulture); + return new ValueTypeConditionResolver + { + Op = op, + Value = value, + ArithmeticExpression = GetArithmeticExpression(parts[0]) + }; + + } + + } + else if (type == typeof(double)) + { + double value = double.Parse(valueStr, CultureInfo.InvariantCulture); + return new ValueTypeConditionResolver + { + Op = ParseValueTypeOperator(operatorStr), + Value = value, + ArithmeticExpression = GetArithmeticExpression(parts[0]) + }; + } + else if (type == typeof(bool)) + { + bool value = bool.Parse(valueStr); + return new BoolConditionResolver + { + Op = ParseBoolOperator(operatorStr), + Value = value, + }; + } + else if (type == typeof(string)) + { + return new StringConditionResolver + { + Op = ParseStringOperator(operatorStr), + Value = valueStr + }; + } + + throw new NotSupportedException($"Type {type} is not supported."); + } + + + private static ValueTypeConditionResolver.Operator ParseValueTypeOperator(string operatorStr) where T : struct, IComparable + { + return operatorStr switch + { + ">" => ValueTypeConditionResolver.Operator.GreaterThan, + "<" => ValueTypeConditionResolver.Operator.LessThan, + "==" => ValueTypeConditionResolver.Operator.Equal, + ">=" => ValueTypeConditionResolver.Operator.GreaterThanOrEqual, + "≥" => ValueTypeConditionResolver.Operator.GreaterThanOrEqual, + "<=" => ValueTypeConditionResolver.Operator.LessThanOrEqual, + "≤" => ValueTypeConditionResolver.Operator.LessThanOrEqual, + "equals" => ValueTypeConditionResolver.Operator.Equal, + "in" => ValueTypeConditionResolver.Operator.InRange, + "!in" => ValueTypeConditionResolver.Operator.OutOfRange, + _ => throw new ArgumentException($"Invalid operator {operatorStr} for value type.") + }; + } + + private static BoolConditionResolver.Operator ParseBoolOperator(string operatorStr) + { + return operatorStr switch + { + "is" => BoolConditionResolver.Operator.Is, + "==" => BoolConditionResolver.Operator.Is, + "equals" => BoolConditionResolver.Operator.Is, + //"isFalse" => BoolConditionNode.Operator.IsFalse, + _ => throw new ArgumentException($"Invalid operator {operatorStr} for bool type.") + }; + } + + private static StringConditionResolver.Operator ParseStringOperator(string operatorStr) + { + return operatorStr switch + { + "c" => StringConditionResolver.Operator.Contains, + "nc" => StringConditionResolver.Operator.DoesNotContain, + "sw" => StringConditionResolver.Operator.StartsWith, + "ew" => StringConditionResolver.Operator.EndsWith, + + "contains" => StringConditionResolver.Operator.Contains, + "doesNotContain" => StringConditionResolver.Operator.DoesNotContain, + "equals" => StringConditionResolver.Operator.Equal, + "==" => StringConditionResolver.Operator.Equal, + "notEquals" => StringConditionResolver.Operator.NotEqual, + "!=" => StringConditionResolver.Operator.NotEqual, + "startsWith" => StringConditionResolver.Operator.StartsWith, + "endsWith" => StringConditionResolver.Operator.EndsWith, + _ => throw new ArgumentException($"Invalid operator {operatorStr} for string type.") + }; + } +} diff --git a/Library/SerinExpression/SerinExpressionEvaluator.cs b/Library/SerinExpression/SerinExpressionEvaluator.cs new file mode 100644 index 0000000..97602c8 --- /dev/null +++ b/Library/SerinExpression/SerinExpressionEvaluator.cs @@ -0,0 +1,207 @@ +using System.Data; + +namespace Serein.Library.SerinExpression +{ + public class SerinArithmeticExpressionEvaluator + { + private static readonly DataTable table = new DataTable(); + + public static double Evaluate(string expression, double inputValue) + { + // 替换占位符@为输入值 + expression = expression.Replace("@", inputValue.ToString()); + try + { + // 使用 DataTable.Compute 方法计算表达式 + var result = table.Compute(expression, string.Empty); + return Convert.ToDouble(result); + } + catch + { + throw new ArgumentException("Invalid arithmetic expression."); + } + } + } + + public class SerinExpressionEvaluator + { + public static object Evaluate(string expression, object targetObJ, out bool IsChange) + { + var parts = expression.Split([' '], 2); + if (parts.Length != 2) + { + throw new ArgumentException("Invalid expression format."); + } + + var operation = parts[0].ToLower(); + var operand = parts[1][0] == '.' ? parts[1][1..] : parts[1]; + + var result = operation switch + { + "@num" => ComputedNumber(targetObJ, operand), + "@call" => InvokeMethod(targetObJ, operand), + "@get" => GetMember(targetObJ, operand), + "@set" => SetMember(targetObJ, operand), + _ => throw new NotSupportedException($"Operation {operation} is not supported.") + }; + + IsChange = operation switch + { + "@num" => true, + "@call" => true, + "@get" => true, + "@set" => false, + _ => throw new NotSupportedException($"Operation {operation} is not supported.") + }; + + return result; + } + + + private static readonly char[] separator = ['(', ')']; + private static readonly char[] separatorArray = [',']; + + private static object InvokeMethod(object target, string methodCall) + { + var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries); + if (methodParts.Length != 2) + { + throw new ArgumentException("Invalid method call format."); + } + + var methodName = methodParts[0]; + var parameterList = methodParts[1]; + var parameters = parameterList.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries) + .Select(p => p.Trim()) + .ToArray(); + + var method = target.GetType().GetMethod(methodName); + if (method == null) + { + throw new ArgumentException($"Method {methodName} not found on target."); + } + + var parameterValues = method.GetParameters() + .Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType)) + .ToArray(); + + + return method.Invoke(target, parameterValues); + + } + + private static object GetMember(object target, string memberPath) + { + var members = memberPath.Split('.'); + foreach (var member in members) + { + + if (target == null) return null; + + + var property = target.GetType().GetProperty(member); + if (property != null) + { + + target = property.GetValue(target); + + } + else + { + var field = target.GetType().GetField(member); + if (field != null) + { + + target = field.GetValue(target); + + } + else + { + throw new ArgumentException($"Member {member} not found on target."); + } + } + } + + + return target; + + } + + private static object SetMember(object target, string assignment) + { + var parts = assignment.Split(new[] { '=' }, 2); + if (parts.Length != 2) + { + throw new ArgumentException("Invalid assignment format."); + } + + var memberPath = parts[0].Trim(); + var value = parts[1].Trim(); + + var members = memberPath.Split('.'); + for (int i = 0; i < members.Length - 1; i++) + { + var member = members[i]; + + var property = target.GetType().GetProperty(member); + + if (property != null) + { + + target = property.GetValue(target); + + } + else + { + var field = target.GetType().GetField(member); + if (field != null) + { + + target = field.GetValue(target); + + } + else + { + throw new ArgumentException($"Member {member} not found on target."); + } + } + } + + var lastMember = members.Last(); + + var lastProperty = target.GetType().GetProperty(lastMember); + + if (lastProperty != null) + { + var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType); + lastProperty.SetValue(target, convertedValue); + } + else + { + var lastField = target.GetType().GetField(lastMember); + if (lastField != null) + { + var convertedValue = Convert.ChangeType(value, lastField.FieldType); + lastField.SetValue(target, convertedValue); + } + else + { + throw new ArgumentException($"Member {lastMember} not found on target."); + } + } + + return target; + } + + private static double ComputedNumber(object value, string expression) + { + double numericValue = Convert.ToDouble(value); + if (!string.IsNullOrEmpty(expression)) + { + numericValue = SerinArithmeticExpressionEvaluator.Evaluate(expression, numericValue); + } + + return numericValue; + } + } +} diff --git a/MyDll/MyDll.csproj b/MyDll/MyDll.csproj index 72543ce..2946f7e 100644 --- a/MyDll/MyDll.csproj +++ b/MyDll/MyDll.csproj @@ -14,6 +14,10 @@ + + + + diff --git a/MyDll/test.cs b/MyDll/test.cs new file mode 100644 index 0000000..ac269d7 --- /dev/null +++ b/MyDll/test.cs @@ -0,0 +1,46 @@ +using IoTClient.Clients.PLC; +using IoTClient.Common.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyDll +{ + internal class test + { + private void T() + { + SiemensClient client = new SiemensClient(SiemensVersion.S7_200Smart, "127.0.0.1", 102); + + //2、写操作 + client.Write("Q1.3", true); + client.Write("V2205", (short)11); + client.Write("V2209", 33); + client.Write("V2305", "orderCode"); //写入字符串 + + //3、读操作 + var value1 = client.ReadBoolean("Q1.3").Value; + var value2 = client.ReadInt16("V2205").Value; + var value3 = client.ReadInt32("V2209").Value; + var value4 = client.ReadString("V2305").Value; //读取字符串 + + //4、如果没有主动Open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动Open和Close。 + client.Open(); + + //5、读写操作都会返回操作结果对象Result + var result = client.ReadInt16("V2205"); + //5.1 读取是否成功(true或false) + var isSucceed = result.IsSucceed; + //5.2 读取失败的异常信息 + var errMsg = result.Err; + //5.3 读取操作实际发送的请求报文 + var requst = result.Requst; + //5.4 读取操作服务端响应的报文 + var response = result.Response; + //5.5 读取到的值 + var value = result.Value; + } + } +} diff --git a/NodeFlow/Model/SingleConditionNode.cs b/NodeFlow/Model/SingleConditionNode.cs index 942b25c..9bb4727 100644 --- a/NodeFlow/Model/SingleConditionNode.cs +++ b/NodeFlow/Model/SingleConditionNode.cs @@ -1,4 +1,5 @@ -using Serein.NodeFlow.SerinExpression; + +using Serein.Library.SerinExpression; namespace Serein.NodeFlow.Model { diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs index 6a3e3a3..041a7e1 100644 --- a/NodeFlow/Model/SingleExpOpNode.cs +++ b/NodeFlow/Model/SingleExpOpNode.cs @@ -1,5 +1,5 @@ -using Serein.NodeFlow; -using Serein.NodeFlow.SerinExpression; +using Serein.Library.SerinExpression; +using Serein.NodeFlow; using System; using System.Collections.Generic; using System.Linq; diff --git a/NodeFlow/Serein.NodeFlow.csproj b/NodeFlow/Serein.NodeFlow.csproj index b8eb682..8a2939e 100644 --- a/NodeFlow/Serein.NodeFlow.csproj +++ b/NodeFlow/Serein.NodeFlow.csproj @@ -9,8 +9,11 @@ + + + diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs index 22282c6..14e24d2 100644 --- a/WorkBench/MainWindow.xaml.cs +++ b/WorkBench/MainWindow.xaml.cs @@ -25,7 +25,9 @@ using static Serein.WorkBench.MainWindow; namespace Serein.WorkBench { - + /// + /// 拖拽创建节点类型 + /// public static class MouseNodeType { public static string RegionType { get; } = nameof(RegionType); @@ -1997,10 +1999,6 @@ namespace Serein.WorkBench return Uri.UnescapeDataString(relativeUri.ToString().Replace('/', System.IO.Path.DirectorySeparatorChar)); } - - - - #region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线 @@ -2251,7 +2249,7 @@ namespace Serein.WorkBench } else if (localhost == Localhost.Right) { - centerPoint.X += halfWidth; + centerPoint.X -= -halfWidth; centerPoint.Y -= direction.Y / Math.Abs(direction.X) * halfHeight - margin; } else if (localhost == Localhost.Top) @@ -2261,7 +2259,7 @@ namespace Serein.WorkBench } else if (localhost == Localhost.Bottom) { - centerPoint.Y += halfHeight; + centerPoint.Y -= -halfHeight; centerPoint.X -= direction.X / Math.Abs(direction.Y) * halfWidth - margin; } diff --git a/WorkBench/Node/View/ActionNodeControl.xaml b/WorkBench/Node/View/ActionNodeControl.xaml index 13ca862..6c968fe 100644 --- a/WorkBench/Node/View/ActionNodeControl.xaml +++ b/WorkBench/Node/View/ActionNodeControl.xaml @@ -22,7 +22,7 @@ - +