Files
DeedyDesigner/DeedyDesigner/Deedy.Activity/Helpers/ElementHelper.cs
2025-09-19 20:25:20 +08:00

242 lines
9.2 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.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
namespace Deedy.Activity
{
public static partial class Helper
{
/// <summary>
/// 查找指定类型的祖辈元素
/// </summary>
/// <typeparam name="T">要查找的祖非类型</typeparam>
/// <param name="element">查找的起点</param>
/// <param name="level">查找的层级默认1级</param>
/// <returns>如果找到根元素也未找到则返回「null」</returns>
public static T? FindAncestorElement<T>(this IElement element, int level = 1) where T : IElement
{
if (element == null || level < 1) return default;
var parent = element.ParentElement;
int currentLevel = 0;
while (parent != null && currentLevel < level)
{
if (parent is T foundParent)
{
// 每次找到一个约定类型的袓辈节点计数需要加1
currentLevel++;
if (currentLevel >= level)
return foundParent;
}
else parent = parent.ParentElement;
}
return default;
}
/// <summary>
/// 设置「IElement」对象的「DepthLevel」属性值
/// </summary>
/// <param name="element">要设置的对象</param>
/// <param name="depthLevel">层级深度</param>
/// <returns>如果设置失败则返回「False」</returns>
public static bool Help_Setter_DepthLevel(this IElement element, int depthLevel)
{
if (element is BasalAction action)
{
ActionSetter_DepthLevel(action, depthLevel);
return true;
}
else
{
try
{
element.SetNamedPropertyValue(nameof(IElement.DepthLevel), depthLevel);
return true;
}
catch { return false; }
}
}
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_DepthLevel")]
private static extern void ActionSetter_DepthLevel(BasalAction action, int value);
/// <summary>
/// 设置「IElement」对象的「ParentElement」属性值
/// </summary>
/// <param name="element">要设置的对象</param>
/// <param name="parent">属性值</param>
/// <returns>如果设置失败则返回「False」</returns>
public static bool Help_Setter_ParentElement(this IElement element, IElement? parent)
{
if (element is BasalAction action)
{
ActionSetter_ParentElement(action, parent);
return true;
}
else
{
try
{
element.SetNamedPropertyValue(nameof(IElement.ParentElement), parent);
return true;
}
catch
{
return false;
}
}
}
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_ParentElement")]
private static extern void ActionSetter_ParentElement(BasalAction action, IElement? value);
/// <summary>
/// 帮助一个IElement节点构建参数映射表
/// </summary>
/// <param name="element">需要构建参数映射表的Element节点</param>
/// <param name="output">消息输出器</param>
public static void Help_BuildParamMapping(this IElement element, Output? output = null)
{
if (element == null) return;
if (element.ParamsMapping == null) element.ParamsMapping = new();
var props = element.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty);
foreach (var prop in props)
{
if (prop.CanWrite && prop.CanRead)
{
var pda = prop.GetCustomAttribute<ParamDefineAttribute>();
if (pda != null)
{
pda.Name = prop.Name;
if (element.ParamsMapping.TryGetParamDefine(prop.Name, out var value)) pda = value;
else element.ParamsMapping.Add(pda);
value.Target = element;
value.Property = prop;
}
}
}
}
/// <summary>
/// 构建一个元素的参数分组,为设计器准备的辅助方法
/// </summary>
/// <param name="element"></param>
/// <param name="output"></param>
/// <returns></returns>
public static ParamGroupCollection Help_BuildParamGroup(this IElement element, Output? output = null)
{
ParamGroupCollection result = new();
if (element != null)
{
result.AddFromType(element.GetType());
result.AppendParamRange(element.ParamsMapping);
}
return result;
}
/// <summary>
/// 构建结构树,设置层级:并且完成参数映射的刷新
/// </summary>
/// <param name="parent">父级元素</param>
public static void Help_Element_ReadyToWorking(this IElement @this, IElement? parent = null, Output? output = null)
{
@this.LinkTo(parent);
if (@this is ICombinedElement combined)
{
combined.Help_CombineElements();
foreach (IElement subElement in combined.Elements)
subElement.ReadyToWorking(@this);
}
}
public static void Help_Element_ReadyToEditing(this IElement @this, Runtime runtime)
{
if (@this is null) return;
@this.SetNamedPropertyValue<Runtime?>(nameof(IActivity.Runtime), runtime);
if (@this is ICombinedElement combined)
{
combined.Help_BuildParamMapping();
foreach (var subElement in combined.Elements)
subElement.ReadyToEditing(runtime);
}
}
/// <summary>
/// 将当前节点链接到一个节点上
/// </summary>
/// <param name="element">要链接到的节点</param>
public static void LinkTo(this IElement @this, [AllowNull] IElement element)
{
if (@this == null) return;
if (element == null)
{
@this.Unlink();
return;
}
if (@this.ParentElement != null)
{
if (@this.ParentElement == element) return;
else
{
if (@this.ParentElement is IContainerElement container)
{
//this.SetNamedPropertyValue(nameof(ParentElement), element);
@this.Help_Setter_ParentElement(element);
}
}
}
else
{
//this.SetNamedPropertyValue(nameof(ParentElement), element);
@this.Help_Setter_ParentElement(element);
}
//this.SetNamedPropertyValue(nameof(DepthLevel), (this.ParentElement?.DepthLevel ?? 0) + 1);
@this.Help_Setter_DepthLevel((@this.ParentElement?.DepthLevel ?? 0) + 1);
}
/// <summary>
/// 断开自身与父级节点的链接关系
/// </summary>
public static void Unlink(this IElement @this)
{
if (@this == null) return;
//this.SetNamedPropertyValue<IElement?>(nameof(ParentElement), null);
@this.Help_Setter_ParentElement(null);
//this.SetNamedPropertyValue(nameof(DepthLevel), 0);
@this.Help_Setter_DepthLevel(0);
}
/// <summary>
/// 克隆一个「IElement」节点
/// </summary>
/// <param name="this">要复制的节点</param>
/// <returns>如果复制失败则返回「null」</returns>
public static IElement? Clone(this IElement @this)
{
if (@this == null) return null;
try
{
return XamlReader.Parse(XamlWriter.Save(@this)) as IElement;
}
catch { return null; }
}
/// <summary>
/// 尝试将一个「IElement」元素序列化为一个字符串形式档案
/// </summary>
/// <param name="this">要序列化的元素</param>
/// <param name="document">序列化后的文本文档</param>
/// <returns>如果出错则返回「Flase」</returns>
public static bool TryEncode(this IElement @this, out string document)
{
bool result = false;
try
{
document = XamlWriter.Save(@this);
result = true;
}
catch { document = string.Empty; }
return result;
}
}
}