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 组件之间的中间缓存层 /// public class XuiFieldTempEntry : IFieldEntry { #region 对象池 internal static ObjectPool Pool { get; private set; } static XuiFieldTempEntry() { Pool = new ObjectPool( createFunc: () => new XuiFieldTempEntry(), actionOnGet: entry => entry.OnEntryCreate(), actionOnRelease: entry => entry.OnEntryRelease(), actionOnDestroy: entry => entry.OnEntryDestroy(), collectionCheck: false, defaultCapacity: 32, maxSize: 512 ); } /// 从池中获取 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 初始化方法 /// /// 设置 Entry 基本属性 /// public void Initialize(string entryName, XuiavrgFieldTag tag = XuiavrgFieldTag.None, int tagIndex = 0) { _entryName = entryName; _entryPath = null; Tag = tag; TagIndex = tagIndex; _fieldOrder = 0; _uiBound = false; } /// /// 设置父 Entry(用于嵌套) /// public void SetParent(IFieldEntry parent) { _parent = parent; _entryPath = null; } /// /// 添加子 Entry /// public void AddChild(XuiFieldTempEntry child) { if (child == null) return; child.SetParent(this); _children.Add(child); } /// /// 添加 MVVM 绑定到此 Entry /// 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 绑定连接 /// 支持主绑定 + 拆分属性子绑定(通过 BindingSlots) /// private void BindComponentWithBinding(XUIAvrgMDValue mdValue) { if (_bindings.Count == 0) return; var primaryBinding = _bindings[0]; // ——— 1. 主绑定:数据 → UI ——— primaryBinding.OnUIDataChanged += value => UpdateUIComponent(mdValue, value); // ——— 主绑定:UI → 数据 ——— WireUpUIEvents(mdValue, primaryBinding); // ——— 2. 拆分属性子绑定匹配 ——— if (primaryBinding.SubBindings?.Count > 0 && mdValue.AvailableBindingSlots?.Count > 0) { // 收集所有子节点上的 XUIAvrgMDValue var childMDValues = new List(); mdValue.GetComponentsInChildren(true, childMDValues); foreach (var slot in mdValue.AvailableBindingSlots) { // 按 propertyName 匹配子绑定 var subBinding = primaryBinding.SubBindings.Find( sb => sb.MetaData?.PropertyPath == slot.propertyName); if (subBinding == null) continue; // 在子节点中查找匹配 Tag 的 XUIAvrgMDValue foreach (var childMD in childMDValues) { if (childMD == mdValue) continue; // 跳过自身 if (childMD.EntryTag == slot.tag || slot.tag == XuiavrgFieldTag.None) { // 子绑定:数据 → UI subBinding.OnUIDataChanged += value => UpdateUIComponent(childMD, value); // 子绑定:UI → 数据(订阅子节点的交互事件) WireUpUIEvents(childMD, subBinding); // 广播子元数据到子节点样式组件 childMD.InitializeWithMetaData(subBinding.MetaData); break; } } } } // 广播主元数据到 XUIAvrgMDValue(触发 IXUIAvrgMDValueStyle 子组件) mdValue.InitializeWithMetaData(primaryBinding.MetaData); } /// /// 订阅 UI 组件的交互事件 → 写入绑定 /// private void WireUpUIEvents(XUIAvrgMDValue mdValue, AvrgMvvmBinding binding) { if (mdValue.TryGetComponent(out UnityEngine.UI.Button uiButton)) { uiButton.onClick.AddListener(() => { binding.WriteFromUI(true); _scheduler?.MarkUIDirty(binding); }); } if (mdValue.TryGetComponent(out UnityEngine.UI.Toggle uiToggle)) { uiToggle.onValueChanged.AddListener(val => { binding.WriteFromUI(val); _scheduler?.MarkUIDirty(binding); }); } if (mdValue.TryGetComponent(out UnityEngine.UI.Slider uiSlider)) { uiSlider.onValueChanged.AddListener(val => { binding.WriteFromUI(val); _scheduler?.MarkUIDirty(binding); }); } if (mdValue.TryGetComponent(out UnityEngine.UI.InputField uiInput)) { uiInput.onEndEdit.AddListener(val => { binding.WriteFromUI(val); _scheduler?.MarkUIDirty(binding); }); } if (mdValue.TryGetComponent(out UnityEngine.UI.Dropdown uiDropdown)) { uiDropdown.onValueChanged.AddListener(val => { binding.WriteFromUI(val); _scheduler?.MarkUIDirty(binding); }); } } /// /// 更新 UI 组件的显示值(通过 XUIAvrgMDValue 所在 GameObject 上的具体组件) /// private static void UpdateUIComponent(XUIAvrgMDValue mdValue, object value) { if (mdValue == null || value == null) return; // Text if (mdValue.TryGetComponent(out UnityEngine.UI.Text uiText)) { uiText.text = value.ToString(); return; } // Toggle if (value is bool boolVal && mdValue.TryGetComponent(out UnityEngine.UI.Toggle uiToggle)) { uiToggle.isOn = boolVal; return; } // Slider if (value is float floatVal && mdValue.TryGetComponent(out UnityEngine.UI.Slider uiSlider)) { uiSlider.value = floatVal; return; } // InputField if (mdValue.TryGetComponent(out UnityEngine.UI.InputField uiInput)) { uiInput.text = value.ToString(); return; } // Dropdown if (value is int intVal && mdValue.TryGetComponent(out UnityEngine.UI.Dropdown uiDropdown)) { uiDropdown.value = intVal; return; } } #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); // 子绑定也做初始值推送 if (binding.SubBindings?.Count > 0) { foreach (var subBinding in binding.SubBindings) { var subValue = subBinding.ReadFromDataSource(); subBinding.NotifyUIUpdate(subValue); } } } } 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 } }