Compare commits

...

5 Commits

Author SHA1 Message Date
DCFApixels
d21c65742b Update package.json 2025-05-14 20:41:36 +08:00
DCFApixels
cb733e8903 Update RuntimeComponentsDrawer.cs 2025-05-14 20:31:01 +08:00
DCFApixels
64bc896457 Update RuntimeComponentsDrawer.cs 2025-05-14 20:26:17 +08:00
DCFApixels
6d0a572c80 refactoring RuntimeComponentsDrawer 2025-05-14 20:21:35 +08:00
DCFApixels
ed499de283 refactoring RuntimeComponentsDrawer 2025-05-14 20:19:40 +08:00
3 changed files with 351 additions and 293 deletions

View File

@ -8,7 +8,7 @@
"displayName": "DragonECS-Unity", "displayName": "DragonECS-Unity",
"description": "Integration with Unity for DragonECS", "description": "Integration with Unity for DragonECS",
"unity": "2021.2", "unity": "2021.2",
"version": "0.5.14", "version": "0.5.14_1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/DCFApixels/DragonECS-Unity.git" "url": "https://github.com/DCFApixels/DragonECS-Unity.git"

View File

@ -15,7 +15,8 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
{ {
internal class RuntimeComponentsDrawer internal class RuntimeComponentsDrawer
{ {
private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags INSTANCE_FIELD_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ResetRuntimeComponentReflectionCache() private static void ResetRuntimeComponentReflectionCache()
{ {
@ -28,6 +29,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
} }
private const int RuntimeComponentsMaxDepth = 2; private const int RuntimeComponentsMaxDepth = 2;
private const int RuntimeComponentsDepthRoot = -1; private const int RuntimeComponentsDepthRoot = -1;
private static RuntimeComponentsDrawer[] _drawers; private static RuntimeComponentsDrawer[] _drawers;
private static int _runtimeComponentsDepth = RuntimeComponentsDepthRoot; private static int _runtimeComponentsDepth = RuntimeComponentsDepthRoot;
static RuntimeComponentsDrawer() static RuntimeComponentsDrawer()
@ -63,35 +65,11 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
internal class RuntimeComponentReflectionCache internal class RuntimeComponentReflectionCache
{ {
public readonly Type Type; public readonly Type Type;
public readonly bool IsUnityObjectType;
public readonly bool IsUnitySerializable;
public readonly bool IsCompositeType;
public readonly bool IsUnmanaged; public readonly bool IsUnmanaged;
public readonly DrawerType DrawerType;
public readonly bool IsLeaf;
public readonly LeafType LeafPropertyType;
public enum LeafType
{
NONE = 0,
Enum,
Bool,
String,
Float,
Double,
Byte,
SByte,
Short,
UShort,
Int,
UInt,
Long,
ULong,
}
public readonly FieldInfoData[] Fields; public readonly FieldInfoData[] Fields;
private RefEditorWrapper[] _wrappers = new RefEditorWrapper[2]; private RefEditorWrapper[] _wrappers = new RefEditorWrapper[RuntimeComponentsMaxDepth];
public RefEditorWrapper GetWrapper(int depth) public RefEditorWrapper GetWrapper(int depth)
{ {
return _wrappers[depth]; return _wrappers[depth];
@ -102,87 +80,88 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
Type = type; Type = type;
ResetWrappers(); ResetWrappers();
IsUnmanaged = UnsafeUtility.IsUnmanaged(type); IsUnmanaged = UnsafeUtility.IsUnmanaged(type);
IsUnityObjectType = typeof(UnityObject).IsAssignableFrom(type);
LeafPropertyType = LeafType.NONE; bool isVoideType = type == typeof(void);
IsLeaf = type.IsPrimitive || type == typeof(string) || type.IsEnum; bool isUnityObjectType = typeof(UnityObject).IsAssignableFrom(type);
bool isLeaf = isUnityObjectType || type.IsPrimitive || type == typeof(string) || type.IsEnum;
if (IsLeaf) DrawerType = DrawerType.UNDEFINED;
if(type.IsArray || isVoideType)
{
DrawerType = DrawerType.Ignored;
}
if (DrawerType == DrawerType.UNDEFINED && isLeaf)
{ {
if (type.IsEnum) if (type.IsEnum)
{ {
LeafPropertyType = LeafType.Enum; DrawerType = type.HasAttribute<FlagsAttribute>() ? DrawerType.EnumFlags : DrawerType.Enum;
}
else if (isUnityObjectType)
{
DrawerType = DrawerType.UnityObject;
} }
else if (type == typeof(bool)) else if (type == typeof(bool))
{ {
LeafPropertyType = LeafType.Bool; DrawerType = DrawerType.Bool;
} }
else if (type == typeof(string)) else if (type == typeof(string))
{ {
LeafPropertyType = LeafType.String; DrawerType = DrawerType.String;
} }
else if (type == typeof(float)) else if (type == typeof(float))
{ {
LeafPropertyType = LeafType.Float; DrawerType = DrawerType.Float;
} }
else if (type == typeof(double)) else if (type == typeof(double))
{ {
LeafPropertyType = LeafType.Double; DrawerType = DrawerType.Double;
} }
else if (type == typeof(byte)) else if (type == typeof(byte))
{ {
LeafPropertyType = LeafType.Byte; DrawerType = DrawerType.Byte;
} }
else if (type == typeof(sbyte)) else if (type == typeof(sbyte))
{ {
LeafPropertyType = LeafType.SByte; DrawerType = DrawerType.SByte;
} }
else if (type == typeof(short)) else if (type == typeof(short))
{ {
LeafPropertyType = LeafType.Short; DrawerType = DrawerType.Short;
} }
else if (type == typeof(ushort)) else if (type == typeof(ushort))
{ {
LeafPropertyType = LeafType.UShort; DrawerType = DrawerType.UShort;
} }
else if (type == typeof(int)) else if (type == typeof(int))
{ {
LeafPropertyType = LeafType.Int; DrawerType = DrawerType.Int;
} }
else if (type == typeof(uint)) else if (type == typeof(uint))
{ {
LeafPropertyType = LeafType.UInt; DrawerType = DrawerType.UInt;
} }
else if (type == typeof(long)) else if (type == typeof(long))
{ {
LeafPropertyType = LeafType.Long; DrawerType = DrawerType.Long;
} }
else if (type == typeof(ulong)) else if (type == typeof(ulong))
{ {
LeafPropertyType = LeafType.ULong; DrawerType = DrawerType.ULong;
} }
} }
if (DrawerType == DrawerType.UNDEFINED)
IsUnitySerializable =
IsUnityObjectType ||
//typeof(Array).IsAssignableFrom(type) ||
//(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) ||
//type.IsPrimitive ||
//type == typeof(string) ||
//type.IsEnum ||
(!type.IsGenericType && type.HasAttribute<System.SerializableAttribute>() && type.IsArray == false);
IsCompositeType =
type.IsPrimitive == false &&
type.IsArray == false &&
type != typeof(string);
if (type == typeof(void)) { return; }
if (IsUnitySerializable == false)
{ {
var fieldInfos = type.GetFields(fieldFlags); DrawerType = type.IsGenericType ? DrawerType.UnityNotSerializableComposite : DrawerType.UnitySerializableComposite;
}
if (isVoideType) { return; }
if (DrawerType == DrawerType.UnityNotSerializableComposite)
{
var fieldInfos = type.GetFields(INSTANCE_FIELD_FLAGS);
Fields = new FieldInfoData[fieldInfos.Length]; Fields = new FieldInfoData[fieldInfos.Length];
for (int i = 0; i < fieldInfos.Length; i++) for (int i = 0; i < fieldInfos.Length; i++)
{ {
@ -204,6 +183,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
public readonly bool IsUnityObjectField; public readonly bool IsUnityObjectField;
public readonly bool IsPassToUnitySerialize; public readonly bool IsPassToUnitySerialize;
public readonly RuntimeComponentReflectionCache ValueTypeReflectionCache; public readonly RuntimeComponentReflectionCache ValueTypeReflectionCache;
public FieldInfoData(FieldInfo fieldInfo) public FieldInfoData(FieldInfo fieldInfo)
{ {
FieldInfo = fieldInfo; FieldInfo = fieldInfo;
@ -448,34 +428,73 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
#region draw data #region draw data
private bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData, int depth) private bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData, int depth)
{ {
const int DEPTH_MAX = 64; const int DEPTH_MAX = 24;
using (EcsGUI.CheckChanged())
{
outData = data; outData = data;
object newData = data;
Type type = data == null ? typeof(void) : data.GetType(); Type type = data == null ? typeof(void) : data.GetType();
RuntimeComponentReflectionCache cache = fieldInfoData.GetReflectionCache(type);
bool isUnityObjectField = fieldInfoData.IsUnityObjectField; bool isUnityObjectField = fieldInfoData.IsUnityObjectField;
if (isUnityObjectField == false && data == null) if (isUnityObjectField == false && data == null)
{ {
EditorGUILayout.TextField(label, "Null"); EditorGUILayout.TextField(label, "Null");
return false; return false;
} }
RuntimeComponentReflectionCache cache = fieldInfoData.GetReflectionCache(type);
if (depth >= DEPTH_MAX || cache == null) if (depth >= DEPTH_MAX || cache == null)
{ {
EditorGUILayout.TextField(label, "error"); EditorGUILayout.TextField(label, "error");
return false; return false;
} }
bool isUnityObjectType = cache.IsUnityObjectType;
ref bool isExpanded = ref expandMatrix.Down(); ref bool isExpanded = ref expandMatrix.Down();
bool changed = false; bool childElementChanged = false;
var eventType = Event.current.type;
if (cache.IsUnitySerializable == false && cache.IsCompositeType) var label2 = UnityEditorUtility.GetLabel2(cache.Type.FullName + " " + type.FullName);
var drawerType = cache.DrawerType;
if (isUnityObjectField)
{ {
drawerType = DrawerType.UnityObject;
}
switch (drawerType)
{
case DrawerType.UNDEFINED:
EditorGUILayout.LabelField(label, label2);
break;
case DrawerType.Ignored:
EditorGUILayout.LabelField(label, label2);
break;
case DrawerType.UnitySerializableComposite:
using (EcsGUI.CheckChanged())
{
RefEditorWrapper wrapper = cache.GetWrapper(_runtimeComponentsDepth);
wrapper.data = data;
wrapper.SO.Update();
wrapper.IsExpanded = isExpanded;
EditorGUILayout.PropertyField(wrapper.Property, label, true);
if (EcsGUI.Changed)
{
wrapper.SO.ApplyModifiedProperties();
newData = wrapper.Data;
childElementChanged = true;
}
isExpanded = wrapper.IsExpanded;
}
break;
case DrawerType.UnityNotSerializableComposite:
GUILayout.Space(EcsGUI.Spacing); GUILayout.Space(EcsGUI.Spacing);
var foldoutStyle = EditorStyles.foldout; var foldoutStyle = EditorStyles.foldout;
Rect rect = GUILayoutUtility.GetRect(label, foldoutStyle); Rect rect = GUILayoutUtility.GetRect(label, foldoutStyle);
rect.xMin += EcsGUI.Indent; //rect.xMin += EcsGUI.Indent;
isExpanded = EditorGUI.BeginFoldoutHeaderGroup(rect, isExpanded, label, foldoutStyle, null, null); isExpanded = EditorGUI.BeginFoldoutHeaderGroup(rect, isExpanded, label, foldoutStyle, null, null);
EditorGUILayout.EndFoldoutHeaderGroup(); EditorGUILayout.EndFoldoutHeaderGroup();
@ -489,184 +508,174 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData, depth + 1)) if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData, depth + 1))
{ {
field.FieldInfo.SetValue(data, fieldData); field.FieldInfo.SetValue(data, fieldData);
outData = data; newData = data;
changed = true; childElementChanged = true;
}
} }
} }
} }
} break;
} case DrawerType.UnityObject:
else
using (EcsGUI.CheckChanged())
{ {
Type fieldType = fieldInfoData.FieldType;
if (isUnityObjectType || isUnityObjectField)
{
EditorGUI.BeginChangeCheck();
var uobj = UnsafeUtility.As<object, UnityObject>(ref data); var uobj = UnsafeUtility.As<object, UnityObject>(ref data);
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldInfoData.FieldType);
var newuobj = EditorGUILayout.ObjectField(label, uobj, fieldInfoData.FieldType, true);
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldType); if (uobj != newuobj)
if (isComponent)
{ {
uobj = EditorGUILayout.ObjectField(label, uobj, typeof(UnityObject), true); if (isComponent && newuobj is GameObject go)
{
newuobj = go.GetComponent(fieldInfoData.FieldType);
}
newData = newuobj;
childElementChanged = true;
} }
else
{
uobj = EditorGUILayout.ObjectField(label, uobj, fieldType, true);
} }
if (EditorGUI.EndChangeCheck()) break;
{ case DrawerType.Enum:
if (isComponent && uobj is GameObject go)
{
uobj = go.GetComponent(fieldType);
}
outData = uobj;
changed = true;
}
}
else
{
EditorGUI.BeginChangeCheck();
RefEditorWrapper wrapper = cache.GetWrapper(_runtimeComponentsDepth);
wrapper.data = data;
try
{
if (fieldInfoData.IsPassToUnitySerialize)
{
if (cache.IsCompositeType)
{
wrapper.SO.Update();
wrapper.IsExpanded = isExpanded;
EditorGUILayout.PropertyField(wrapper.Property, label, true);
if (GUI.changed)
{
wrapper.SO.ApplyModifiedProperties();
}
}
else if (cache.IsLeaf)
{
var eventType = Event.current.type;
switch (cache.LeafPropertyType)
{
//case RuntimeComponentReflectionCache.LeafType.Enum:
// break;
case RuntimeComponentReflectionCache.LeafType.Bool:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = EditorGUILayout.Toggle(label, (bool)data); var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumPopup(label, enumData);
}
else
{
EditorGUILayout.EnumPopup(label, default);
}
break;
case DrawerType.EnumFlags:
if (eventType != EventType.Layout)
{
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumFlagsField(label, enumData);
}
else
{
EditorGUILayout.EnumFlagsField(label, default);
}
break;
case DrawerType.Bool:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.Toggle(label, (bool)data);
} }
else else
{ {
EditorGUILayout.Toggle(label, default); EditorGUILayout.Toggle(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.String: case DrawerType.String:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = EditorGUILayout.TextField(label, (string)data); newData = EditorGUILayout.TextField(label, (string)data);
} }
else else
{ {
EditorGUILayout.TextField(label, default); EditorGUILayout.TextField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.Float: case DrawerType.Float:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = EditorGUILayout.FloatField(label, (float)data); newData = EditorGUILayout.FloatField(label, (float)data);
} }
else else
{ {
EditorGUILayout.FloatField(label, default); EditorGUILayout.FloatField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.Double: case DrawerType.Double:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = EditorGUILayout.DoubleField(label, (double)data); newData = EditorGUILayout.DoubleField(label, (double)data);
} }
else else
{ {
EditorGUILayout.DoubleField(label, default); EditorGUILayout.DoubleField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.Byte: case DrawerType.Byte:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (byte)EditorGUILayout.IntField(label, (byte)data); newData = (byte)EditorGUILayout.IntField(label, (byte)data);
} }
else else
{ {
EditorGUILayout.IntField(label, default); EditorGUILayout.IntField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.SByte: case DrawerType.SByte:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (sbyte)EditorGUILayout.IntField(label, (sbyte)data); newData = (sbyte)EditorGUILayout.IntField(label, (sbyte)data);
} }
else else
{ {
EditorGUILayout.IntField(label, default); EditorGUILayout.IntField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.Short: case DrawerType.Short:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (short)EditorGUILayout.IntField(label, (short)data); newData = (short)EditorGUILayout.IntField(label, (short)data);
} }
else else
{ {
EditorGUILayout.IntField(label, default); EditorGUILayout.IntField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.UShort: case DrawerType.UShort:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (ushort)EditorGUILayout.IntField(label, (ushort)data); newData = (ushort)EditorGUILayout.IntField(label, (ushort)data);
} }
else else
{ {
EditorGUILayout.IntField(label, default); EditorGUILayout.IntField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.Int: case DrawerType.Int:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (int)EditorGUILayout.IntField(label, (int)data); newData = (int)EditorGUILayout.IntField(label, (int)data);
} }
else else
{ {
EditorGUILayout.IntField(label, default); EditorGUILayout.IntField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.UInt: case DrawerType.UInt:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (uint)EditorGUILayout.IntField(label, (int)(uint)data); newData = (uint)EditorGUILayout.IntField(label, (int)(uint)data);
} }
else else
{ {
EditorGUILayout.IntField(label, default); EditorGUILayout.IntField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.Long: case DrawerType.Long:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = EditorGUILayout.LongField(label, (long)data); newData = EditorGUILayout.LongField(label, (long)data);
} }
else else
{ {
EditorGUILayout.LongField(label, default); EditorGUILayout.LongField(label, default);
} }
break; break;
case RuntimeComponentReflectionCache.LeafType.ULong: case DrawerType.ULong:
if (eventType != EventType.Layout) if (eventType != EventType.Layout)
{ {
wrapper.data = (ulong)EditorGUILayout.LongField(label, (long)(ulong)data); newData = (ulong)EditorGUILayout.LongField(label, (long)(ulong)data);
} }
else else
{ {
@ -674,40 +683,46 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
} }
break; break;
default: default:
EditorGUILayout.LabelField(label); EditorGUILayout.LabelField(label, label2);
break; break;
} }
}
}
else
{
EditorGUILayout.LabelField(label);
}
}
catch (ArgumentException)
{
if (Event.current.type != EventType.Repaint)
{
throw;
}
}
finally
{
if (EditorGUI.EndChangeCheck())
{
outData = wrapper.Data;
changed = true;
}
isExpanded = wrapper.IsExpanded;
}
}
}
expandMatrix.Up(); expandMatrix.Up();
return changed; if (childElementChanged || EcsGUI.Changed)
{
outData = newData;
return true;
}
}
return false;
} }
#endregion #endregion
public enum DrawerType
{
UNDEFINED = 0,
Ignored,
// Composite
UnitySerializableComposite,
UnityNotSerializableComposite,
// Leaft types
UnityObject,
Enum,
EnumFlags,
Bool,
String,
Float,
Double,
Byte,
SByte,
Short,
UShort,
Int,
UInt,
Long,
ULong,
}
} }
} }
#endif #endif

View File

@ -235,6 +235,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
//private static Type[] _noHiddenSerializableTypes; //private static Type[] _noHiddenSerializableTypes;
private static GUIContent _singletonIconContent = null; private static GUIContent _singletonIconContent = null;
private static GUIContent _singletonContent = null; private static GUIContent _singletonContent = null;
private static GUIContent _singleton2Content = null;
private static GUIStyle _inputFieldCenterAnhor = null; private static GUIStyle _inputFieldCenterAnhor = null;
private static Dictionary<Type, MonoScript> _scriptsAssets = new Dictionary<Type, MonoScript>(256); private static Dictionary<Type, MonoScript> _scriptsAssets = new Dictionary<Type, MonoScript>(256);
@ -440,6 +441,17 @@ namespace DCFApixels.DragonECS.Unity.Editors
_singletonIconContent.tooltip = tooltip; _singletonIconContent.tooltip = tooltip;
return _singletonIconContent; return _singletonIconContent;
} }
public static GUIContent GetLabel2(string name, string tooltip = null)
{
if (_singleton2Content == null)
{
_singleton2Content = new GUIContent();
}
_singleton2Content.text = name;
_singleton2Content.image = null;
_singleton2Content.tooltip = tooltip;
return _singleton2Content;
}
#endregion #endregion
#region GetDefaultStyle #region GetDefaultStyle
@ -517,6 +529,37 @@ namespace DCFApixels.DragonECS.Unity.Editors
return result; return result;
} }
#endregion #endregion
//private static StructList<GUIContent> _stackLabels = new StructList<GUIContent>(4);
//public static StackTempLabelScope GetStackLabel(string text, string tooltip = null)
//{
// StackTempLabelScope result = default;
// if (_stackLabels.Count <= 0)
// {
// result = new StackTempLabelScope(new GUIContent());
// }
// else
// {
// var l = _stackLabels[_stackLabels.Count - 1];
// _stackLabels.RemoveAt(_stackLabels.Count - 1);
// result = new StackTempLabelScope(l);
// }
// result.Label.text = text;
// result.Label.tooltip = tooltip;
// return result;
//}
//private static void ReturnStackLabel(GUIContent label)
//{
// _stackLabels.Add(label);
//}
//public readonly struct StackTempLabelScope : IDisposable
//{
// public readonly GUIContent Label;
// public StackTempLabelScope(GUIContent label) { Label = label; }
// public void Dispose() { ReturnStackLabel(Label); }
// public static implicit operator GUIContent(StackTempLabelScope a) { return a.Label; }
//}
} }
internal static class RuntimeComponentsUtility internal static class RuntimeComponentsUtility