Files
DeedyDesigner/DeedyDesigner/Deedy.Activity/Helpers/ActionHelper.cs
2025-09-19 19:33:24 +08:00

267 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace Deedy.Activity
{
public static partial class Helper
{
private static readonly Dictionary<Type, (List<CombineRule_AllowTypeAttribute>, List<CombineRule_RejectTypeAttribute>)> StaticField_CombineRules = [];
/// <summary>
/// 查询可动态组装集合的组合规则
/// </summary>
/// <param name="element">要查询的元素</param>
/// <param name="allowTypes">允许规则集合</param>
/// <param name="rejectTypes">禁止规则集合</param>
public static void Help_GetCombineRules(this IContainerElement element,
ref List<CombineRule_AllowTypeAttribute> allowTypes,
ref List<CombineRule_RejectTypeAttribute> rejectTypes)
{
if (element == null) return;
Type type = element.GetType();
if (!StaticField_CombineRules.ContainsKey(type))
{
var _AllowTypes = new List<CombineRule_AllowTypeAttribute>();
var _RejectTypes = new List<CombineRule_RejectTypeAttribute>();
var clearRule = type.GetCustomAttribute<CombineRule_ClearInheritedAttribute>(false);
if (clearRule != null)
{
var allowRules = type.GetCustomAttributes<CombineRule_AllowTypeAttribute>(false);
foreach (var rule in allowRules) _AllowTypes.Add(rule);
var rejectRules = type.GetCustomAttributes<CombineRule_RejectTypeAttribute>(false);
foreach (var rule in rejectRules) _RejectTypes.Add(rule);
}
else
{
//沿着继承链查找具备「CombineRule_ClearInheritedAttribute」特性的类型获取组装属性
List<Type> types = [];
Type? baseType = type.BaseType;
while (baseType != null)
{
types.Add(baseType);
clearRule = baseType.GetCustomAttribute<CombineRule_ClearInheritedAttribute>(false);
if (clearRule != null) break;
baseType = baseType.BaseType;
}
foreach (var ruleType in types)
{
var aRules = ruleType.GetCustomAttributes<CombineRule_AllowTypeAttribute>(false);
foreach (var rule in aRules) _AllowTypes.Add(rule);
var rRules = ruleType.GetCustomAttributes<CombineRule_RejectTypeAttribute>(false);
foreach (var rule in rRules) _RejectTypes.Add(rule);
}
}
StaticField_CombineRules.Add(type, (allowTypes, rejectTypes));
}
(List<CombineRule_AllowTypeAttribute> allowTypes, List<CombineRule_RejectTypeAttribute> rejectTypes) rules
= StaticField_CombineRules[type];
allowTypes.AddRange(rules.allowTypes);
rejectTypes.AddRange(rules.rejectTypes);
}
/// <summary>
/// 如果类型上没有组装规则,则认为不允许组装,否则按照组装规则处理
/// </summary>
/// <param name="container">要校验的可动态组装容器</param>
/// <param name="element">要进行组装检查的单元实例</param>
/// <param name="effects">校验结果</param>
/// <returns>是否允许组装</returns>
public static bool Help_CombineChecking(this IContainerElement container, IElement element, out DragDropEffects effects)
{
DragDropEffects resultEffects = DragDropEffects.None;
List<CombineRule_AllowTypeAttribute> _AllowTypes = [];
List<CombineRule_RejectTypeAttribute> _RejectTypes = [];
Help_GetCombineRules(container, ref _AllowTypes, ref _RejectTypes);
if (element == null)
{
effects = resultEffects;
return false;
}
// 如果没有组装规则则直接返回
if (_AllowTypes.Count == 0 && _RejectTypes.Count == 0)
{
effects = resultEffects;
return false;
}
Type uType = element.GetType();
bool allow = false;
foreach (var aRule in _AllowTypes)
{
if (aRule.BaseType.IsAssignableFrom(uType))
{
if (!aRule.Excluded.Contains(uType))
{
allow = true;
break;
}
}
}
if (!allow)
{
effects = resultEffects;
return allow; // 如果没有匹配的放行规则则直接返回
}
resultEffects |= DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link;
foreach (var rRule in _RejectTypes)
{
if (rRule.BaseType.IsAssignableFrom(uType))
{
if (!rRule.Excluded.Contains(uType))
{
resultEffects &= DragDropEffects.None;
allow = false;
break;
}
}
}
effects = resultEffects;
return allow;
}
/// <summary>
/// 将使用部件声明特性声明的动作部件与主体组装到一起并连接
/// </summary>
/// <param name="combined">要进行组装的组合元素</param>
public static void Help_CombineElements(this ICombinedElement combined)
{
if (combined == null) return;
if (combined.Elements == null) combined.Elements = [];
var props = combined.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField);
SortedList<int, IElement> sortedElements = new();
Dictionary<string, PropertyInfo> properties = new();
foreach (var prop in props)
{
if (!prop.CanRead || !prop.CanWrite) continue;
if (!prop.PropertyType.IsAssignableFrom(typeof(IElement))) continue;
var cpd = prop.GetCustomAttribute<CombinePartActionAttribute>();
if (cpd == null) continue;
var element = prop.GetValue(combined) as IElement;
if (element == null) continue;
element.Help_SetAttachValue(CombinePartActionAttribute.CombinePartSign, prop.Name);
sortedElements.Add(cpd.InitialSort, element);
properties.Add(prop.Name, prop);
}
foreach (var partElement in sortedElements.Values)
{
string partSign = partElement.Help_GetAttachValue(CombinePartActionAttribute.CombinePartSign);
if (string.IsNullOrEmpty(partSign)) continue;
bool hasPart = false;
foreach (var element in combined.Elements)
{
if (element.Help_GetAttachValue(CombinePartActionAttribute.CombinePartSign) == partSign)
{
element.LinkTo(combined);
properties[partSign].SetValue(combined, element);
hasPart = true;
break;
}
}
if (!hasPart)
{
combined.Elements.Add(partElement);
partElement.LinkTo(combined);
if (partElement is IActionElement actionElement) actionElement.IsLocked = true;
}
}
}
/// <summary>
/// 将一个元素插入到可变容器的指定位置
/// </summary>
/// <param name="this">可变元素容器</param>
/// <param name="element">要插入的元素</param>
/// <param name="index">要插入的位置</param>
public static void Help_Insert(this IContainerElement @this, IElement element, uint index)
{
if (element == null) return;
if (index < @this.Elements.Count) @this.Elements.Insert((int)index, element);
if (index >= @this.Elements.Count) @this.Elements.Add(element);
}
/// <summary>
/// 将一个元素移动到容器的指定位置
/// </summary>
/// <param name="this">可变元素容器</param>
/// <param name="element">要移动的元素</param>
/// <param name="index">要移动到的位置</param>
public static void Help_MoveTo(this IContainerElement @this, IElement element, uint index)
{
if (element == null) return;
int newIndex = (index >= @this.Elements.Count) ? @this.Elements.Count - 1 : (int)index;
int oldIndex = @this.Elements.IndexOf(element);
if (oldIndex < 0) @this.Help_Insert(element, (uint)newIndex);
else @this.Elements.Move(oldIndex, newIndex);
}
/// <summary>
/// 将一个元素插入到当前节点前方「前提:当前节点的父级必须是可变容器节点」
/// </summary>
/// <param name="element">当前节点</param>
/// <param name="insertion">待插入的节点</param>
public static void Help_InsertElementToFore(this IElement element, IElement insertion)
{
if (element == null || insertion == null || insertion.ParentElement is ICombinedElement) return;
//TODO在当前节点前方插入新节点
}
/// <summary>
/// 将一个元素插入到当前节点后方「前提:当前节点的父级必须是可变容器节点」
/// </summary>
/// <param name="element">当前节点</param>
/// <param name="insertion">待插入的节点</param>
public static void Help_InsertElementAtRear(this IElement element, IElement insertion)
{
if (element == null || insertion == null || insertion.ParentElement is ICombinedElement) return;
//TODO在当前节点的后方插入新节点
}
/// <summary>
/// 将当前节点从父节点中移除
/// </summary>
/// <param name="element">要移除的元素</param>
public static void Help_RemoveFromParent(this IElement element)
{
if (element != null && element.ParentElement is IContainerElement container) container.Remove(element);
//TODO将当前节点从自身的父级节点中移除
}
/// <summary>
/// 调整子节点的退出线位置
/// </summary>
/// <param name="container">要调整的带退出线容器</param>
public static void Help_AdjustExitlinePosition(this IContainerWithExitline container)
{
if (container != null
&& (container.ExitlinePosition == ExitlinePosition.LeftLower
|| container.ExitlinePosition == ExitlinePosition.Rightlower))
{
var lastChild = container.Elements[container.Elements.Count - 1] as IContainerWithExitline;
if (lastChild != null
&& (lastChild.ExitlinePosition == ExitlinePosition.LeftLower
|| lastChild.ExitlinePosition == ExitlinePosition.Rightlower))
{
if (container.IsExitlineAtSamePosition == true)
{
if (container.ExitlinePosition == ExitlinePosition.LeftLower)
lastChild.ExitlinePosition = ExitlinePosition.LeftLower;
if (container.ExitlinePosition == ExitlinePosition.Rightlower)
lastChild.ExitlinePosition = ExitlinePosition.Rightlower;
}
if (container.IsExitlineAtSamePosition == false)
{
if (container.ExitlinePosition == ExitlinePosition.LeftLower)
lastChild.ExitlinePosition = ExitlinePosition.LeftLower;
if (container.ExitlinePosition == ExitlinePosition.Rightlower)
lastChild.ExitlinePosition = ExitlinePosition.Rightlower;
}
}
}
}
}
}