267 lines
12 KiB
C#
267 lines
12 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|