242 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
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;
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 |