using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Pool; namespace XericUI.ReflectionUIGenerator { /// /// 字段 Entry 接口 /// 数据对象字段与 UI 组件之间的中间缓存层 /// public interface IFieldEntry { /// Entry 名称(字段名或编组路径) string EntryName { get; } /// Entry 完整路径(含父级路径) string EntryPath { get; } /// 主要功能标记 XuiavrgFieldTag Tag { get; } /// 标记索引 int TagIndex { get; } /// 排序值(越小越靠前) int FieldOrder { get; set; } /// 是否为编组 Entry(包含子 Entry) bool IsGroupEntry { get; } /// 父 Entry IFieldEntry Parent { get; } /// 子 Entry 列表(只读) IReadOnlyList Children { get; } /// 生成的 UI 实例引用 GameObject UIInstance { get; } /// 绑定的预制体引用 GameObject BoundPrefab { get; set; } /// 关联的 MVVM 绑定列表 IReadOnlyList Bindings { get; } // === 生命周期 === /// Entry 创建时调用 void OnEntryCreate(); /// 绑定 UI 和数据时调用 void OnEntryBind(); /// 释放时调用(归还池前) void OnEntryRelease(); /// 销毁时调用 void OnEntryDestroy(); // === 绑定管理 === /// 添加 MVVM 绑定到此 Entry void AddBinding(AvrgMvvmBinding binding, AvrgMvvmScheduler scheduler); // === UI 绑定 === /// /// 绑定 UI 组件 /// void BindUIComponent(GameObject uiInstance, List componentCache); } /// /// 字段临时 Entry 实现类 /// 作为数据对象和 UI 组件之间的中间缓存层 /// /// UI 交互事件的分配通过 XUIAvrgMDValue.BindToAccessor() 的多态机制完成, /// 各类 XUIAvrgMDValue 子类自行管理其专属 UI 组件的交互订阅。 /// public class XuiFieldTempEntry : IFieldEntry { #region 对象池 private static ObjectPool _pool; internal static ObjectPool Pool { get { if (_pool == null) { _pool = new ObjectPool( createFunc: () => new XuiFieldTempEntry(), actionOnGet: entry => entry.OnEntryCreate(), actionOnRelease: entry => entry.OnEntryRelease(), actionOnDestroy: entry => entry.OnEntryDestroy(), collectionCheck: false, defaultCapacity: 32, maxSize: 512 ); } return _pool; } } /// 从池中获取 Entry 实例 public static XuiFieldTempEntry Get() => Pool.Get(); /// 将 Entry 归还池中 public static void Release(XuiFieldTempEntry entry) => Pool.Release(entry); #endregion #region 字段 private string _entryName; private string _entryPath; private IFieldEntry _parent; private List _children = new List(); private List _bindings = new List(); private AvrgMvvmScheduler _scheduler; private GameObject _uiInstance; private GameObject _boundPrefab; private int _fieldOrder; private bool _uiBound; #endregion #region IFieldEntry 属性实现 public string EntryName => _entryName; public string EntryPath { get { if (!string.IsNullOrEmpty(_entryPath)) return _entryPath; if (_parent != null) { string parentPath = _parent.EntryPath; return string.IsNullOrEmpty(parentPath) ? _entryName : parentPath + "/" + _entryName; } return _entryName; } } public XuiavrgFieldTag Tag { get; private set; } public int TagIndex { get; private set; } public int FieldOrder { get => _fieldOrder; set => _fieldOrder = value; } public bool IsGroupEntry => _children.Count > 0; public IFieldEntry Parent => _parent; public IReadOnlyList Children => _children; public GameObject UIInstance => _uiInstance; public GameObject BoundPrefab { get => _boundPrefab; set => _boundPrefab = value; } public IReadOnlyList Bindings => _bindings; #endregion #region 初始化方法 public void Initialize(string entryName, XuiavrgFieldTag tag = XuiavrgFieldTag.None, int tagIndex = 0) { _entryName = entryName; _entryPath = null; Tag = tag; TagIndex = tagIndex; _fieldOrder = 0; _uiBound = false; } public void SetParent(IFieldEntry parent) { _parent = parent; _entryPath = null; } public void AddChild(XuiFieldTempEntry child) { if (child == null) return; child.SetParent(this); _children.Add(child); } public void AddBinding(AvrgMvvmBinding binding, AvrgMvvmScheduler scheduler) { if (binding == null) return; _bindings.Add(binding); _scheduler = scheduler; if (Tag == XuiavrgFieldTag.None && binding.MetaData?.Tag != XuiavrgFieldTag.None) { Tag = binding.MetaData.Tag; TagIndex = binding.MetaData.TagIndex; } } #endregion #region UI 绑定 public void BindUIComponent(GameObject uiInstance, List componentCache) { _uiInstance = uiInstance; if (_uiInstance == null || _uiBound) return; if (componentCache == null) { componentCache = new List(); _uiInstance.GetComponentsInChildren(true, componentCache); } // 遍历组件缓存,寻找 XUIAvrgMDValue 按 Tag 匹配 foreach (var comp in componentCache) { if (comp is XUIAvrgMDValue mdValue) { if (mdValue.EntryTag == this.Tag && (this.TagIndex == 0 || mdValue.TagIndex == this.TagIndex)) { BindComponentWithBinding(mdValue); } } } // 子 Entry 复用组件缓存 foreach (var child in _children) { child.BindUIComponent(_uiInstance, componentCache); } _uiBound = true; } /// /// 将 XUIAvrgMDValue 与 MVVM 绑定连接 /// 通过多态 BindToAccessor 让 UI 子类自行管理交互事件和显示更新 /// private void BindComponentWithBinding(XUIAvrgMDValue mdValue) { if (_bindings.Count == 0) return; var primaryBinding = _bindings[0]; // ★ 多态调用: UI 子类自行处理交互事件和显示更新 mdValue.BindToAccessor(primaryBinding.Accessor, primaryBinding, _scheduler); // 拆分属性子绑定处理 if (primaryBinding.SubBindings?.Count > 0 && mdValue.AvailableBindingSlots?.Count > 0) { var childMDValues = new List(); mdValue.GetComponentsInChildren(true, childMDValues); foreach (var slot in mdValue.AvailableBindingSlots) { var subBinding = primaryBinding.SubBindings.Find( sb => sb.MetaData?.PropertyPath == slot.propertyName); if (subBinding == null) continue; foreach (var childMD in childMDValues) { if (childMD == mdValue) continue; if (childMD.EntryTag == slot.tag || slot.tag == XuiavrgFieldTag.None) { childMD.BindToAccessor(subBinding.Accessor, subBinding, _scheduler); childMD.InitializeWithMetaData(subBinding.MetaData); break; } } } } // 广播主元数据到样式组件 mdValue.InitializeWithMetaData(primaryBinding.MetaData); } #endregion #region 生命周期 public void OnEntryCreate() { _entryName = null; _entryPath = null; _parent = null; _fieldOrder = 0; _uiBound = false; } public void OnEntryBind() { foreach (var binding in _bindings) { var value = binding.ReadFromDataSource(); binding.NotifyUIUpdate(value, ValidationState.Normal); if (binding.SubBindings?.Count > 0) { foreach (var subBinding in binding.SubBindings) { var subValue = subBinding.ReadFromDataSource(); subBinding.NotifyUIUpdate(subValue, ValidationState.Normal); } } } } public void OnEntryRelease() { _entryName = null; _entryPath = null; _parent = null; _uiInstance = null; _boundPrefab = null; Tag = XuiavrgFieldTag.None; TagIndex = 0; _fieldOrder = 0; _uiBound = false; foreach (var binding in _bindings) { binding.ClearUIEvent(); if (binding.SubBindings?.Count > 0) { foreach (var sub in binding.SubBindings) sub.ClearUIEvent(); } } _bindings.Clear(); _scheduler = null; foreach (var child in _children) { Release(child); } _children.Clear(); } public void OnEntryDestroy() { foreach (var binding in _bindings) { binding.ClearUIEvent(); if (binding.SubBindings?.Count > 0) { foreach (var sub in binding.SubBindings) sub.ClearUIEvent(); } } _bindings.Clear(); _children.Clear(); _uiInstance = null; _scheduler = null; } #endregion } }